如果我访问链接共享库的可执行文件中的单例,然后访问共享库中的相同单例,则会创建两个实例。
这是不允许的还是我做错了什么?
这里有一些代码可供说明。我创建了一个包含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
然后我在使用管理器的同一个库中有一个窗口类。
这是h(DECLSPEC在DeclSpec.h中定义并处理库导出/导入):
#ifndef WINDOW_H
#define WINDOW_H
#include "DeclSpec.h"
class DECLSPEC Window
{
public:
Window();
};
#endif //WINDOW_H
这是cpp:
#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 :(得分:0)
就像任何其他类一样,您需要告诉编译器导出或导入模板类专门化。以下是如何正确地将模板专业化声明为导入或导出。
#ifndef MANAGER_H
#define MANAGER_H
#include "Singleton.h"
// <BEGIN modifications>
// forward declare the Manager class
class Manager;
// delcare your specialization as import or export
// NOTE: this only works on win32.
// For other platforms you would use the 'extern' keyword, and it does not go in the same place as DECLSPEC
template class DECLSPEC Singleton<Manager>;
// <END modifications>
class Manager : public Singleton<Manager>
{
};
#endif //MANAGER_H
此处的目标是使用DECLSPEC标记Singleton的特定专业化。我们不想标记模板类本身,因为您可能希望拥有其他类型的单例,而这些单体不会存在于主可执行文件中。
microsoft编译器不会实现用declspec标记的模板。其他编译器(clang,gcc)使用&#39; extern&#39;用于此目的的关键字。因此,您有责任在其中一个cpp文件中显式实例化模板。如果您忘记这样做,您将获得链接器错误,就像您创建了类成员函数并忘记实现它一样。
相反,如果你忘记在没有DECLSPEC的情况下在代码中的某处引用Singleton(就像你转发声明该类一样),你将得到多个符号定义&#39;链接器错误。
所以将以下内容添加到Manager.cpp中以强制编译器完全实例化Singleton的模板特化:
template class Singleton<Manager>;