2014-11-17 2 views
1

Если я получаю доступ к одиночному элементу в исполняемом файле, который связан с общей библиотекой и затем получает доступ к одному и тому же одноэлементу в общей библиотеке, создаются два экземпляра.Несколько экземпляров Singleton в общей библиотеке C++ в Windows

Нельзя ли это сделать, или я делаю что-то неправильно?

Вот несколько примеров для иллюстрации. Я создаю общую библиотеку, содержащую Singleton.h, Manager.h, window.h, window.cpp и DeclSpec.h

класс

Singleton шаблон:

#ifndef SINGLETON_H 
#define SINGLETON_H 

#include <memory> 
#include <iostream> 

template <typename T> 
class Singleton 
{ 
private: 
    static std::unique_ptr<T> s_instance; 

public: 
    static T &instance() 
    { 
     if (!s_instance) { 
      std::cout << "Creating..." << std::endl; 
      s_instance = std::make_unique<T>(); 
     } 

     return *s_instance; 
    } 
}; 

template <typename T> 
std::unique_ptr<T> Singleton<T>::s_instance; 

#endif //SINGLETON_H 

создать класс менеджера, который одноэлементно :

#ifndef MANAGER_H 
#define MANAGER_H 

#include "Singleton.h" 

class Manager : public Singleton<Manager> 
{ 
}; 

#endif //MANAGER_H 

Тогда у меня есть класс окна в той же библиотеке, где используется менеджер.

Вот ч (DECLSPEC определяется в DeclSpec.h и обрабатывает библиотеку экспорта/импорта):

#ifndef WINDOW_H 
#define WINDOW_H 

#include "DeclSpec.h" 

class DECLSPEC Window 
{ 

public: 
    Window(); 

}; 

#endif //WINDOW_H 

Вот каст:

#include "Manager.h" 
#include "Window.h" 

Window::Window() 
{ 
    Manager &m = Manager::instance(); 
} 

Наконец, я создаю исполняемый связан с указанной выше общей библиотекой с простым main.cpp:

#include "Manager.h" 
#include "Window.h" 

int main(void) 
{ 
    Manager &m = Manager::instance(); 
    Window w; 

    return 0; 
} 

выход:

Creating... 
Creating... 

Синглтон создан дважды.

Любые указатели?

+0

Используйте завод, как предложенный Hans Passant, или просто использовать экспортируемые функции в пространстве имен Я описал здесь: http://stackoverflow.com/a/26954789/805509 и экспортировал их.Если это вариант для вас, оставьте комментарий, и я дам полный ответ. Но определенно нет, если вам нужно использовать такие вещи, как «Диспетчер» в качестве класса или иметь указатель на экземпляр где-то. – PuerNoctis

ответ

0

Как и любой другой класс, вам нужно сообщить компилятору, что он экспортирует или импортирует специализацию класса шаблона. Вот как правильно объявить специализацию вашего шаблона как импорт или экспорт.

Целью является отметить специальную специализацию Singleton с помощью DECLSPEC. Мы не хотим отмечать сам шаблонный шаблон, потому что вы можете захотеть иметь одиночные списки других типов, которые не живут в вашем основном исполняемом файле.

Компилятор microsoft не реализует шаблоны с тегами declspec. Другие компиляторы (clang, gcc) используют ключевое слово 'extern' для этой цели. Таким образом, вы несете ответственность за явное создание шаблона в одном из ваших файлов cpp. Если вы забудете сделать это, вы получите ошибки компоновщика так же, как вы сделали функцию члена класса, и забыли реализовать ее.

И наоборот, если вы забыли указать Синглтон где-нибудь в своем коде без DECLSPEC (например, если вы переадресовываете объявление класса), вы получите «множественные символы, определенные» ошибки компоновщика.

Так что добавьте следующие строки в Manager.cpp, чтобы заставить компилятор полностью экземпляр шаблона специализации вашей Singleton:

template class Singleton<Manager>;