这个头文件中的实现有什么问题?
template <typename T>
class Singleton
{
public:
static T* getInstance()
{
if (m_instance == NULL)
{
m_instance = new T();
}
return m_instance;
}
private:
static T* m_instance;
};
我这样使用它:
typedef Singleton<MyClass> MyClassSingleton;
我得到链接错误:
error LNK2001: unresolved external symbol "private: static class MyClass * Singleton<class MyClass>::m_instance" (?m_instance@?$Singleton@VMyClass@@@@0PAVMyClass@@A)
添加
template <typename T> T* Singleton<T>::m_instance = NULL;
它可以工作,但是我担心两件事:
- 静态成员应该在.cpp文件中定义,以便在所有编译单元中只有一个实例,即使您将头文件包含在10个源文件中。
- 指针被初始化为NULL标准,为什么我需要显式初始化?
您可以通过在类定义之后添加m_instance
成员的定义来修复您的错误。
template<typename T>
T* Singleton<T>::m_instance = nullptr;
对于类模板,在头文件中添加static
成员的定义是可以的,并且不会导致ODR冲突。
但是,正如其他人建议的那样,最好将getInstance()
定义更改为
static T& getInstance()
{
static T instance;
return instance;
}
c++ 11甚至保证局部static
函数变量instance
的创建将是线程安全的。
静态成员总是只需要初始化一次,包括那些来自模板实例化的成员。
如果你真的喜欢,你可以用局部静态来避免这种情况:
template <typename T>
T *Singleton<T>::getInstance() {
// Will be lazy initialized on first call (instead of startup) probably.
static T instance;
return &instance;
}
或:
// No need to use pointers, really...
template <typename T>
T &Singleton<T>::getInstance() {
static T instance;
return instance
};
如果你真的想使用单例,并且你真的确定你想使用模板化的单例,你可能想使用Scott Meyer的单例方法:
template <typename T>
class Singleton
{
public:
static Singleton<T>& getInstance() {
static Singleton<T> theInstance;
return theInstance;
}
private:
Singleton() {}
Singleton(const Singleton<T>&);
Singleton<T>& operator=(const Singleton<T>&);
};
指针被标准初始化为NULL,为什么我需要这样做显式初始化?
你不需要。
template <typename T>
T* Singleton<T>::m_instance;
作为静态&全局变量默认为零初始化
具有静态存储时间(3.7.1)或线程存储时间(3.7.2)的变量应进行零初始化(8.5)
其他人已经回答了如何修复代码,但您的问题也是关于推理的。通过解释,你所纠结的是声明和定义之间的区别。这一行:
static T* m_instance;
你声明m_instance有一个名字,但是你还没有定义这个空间。您添加的那行代码定义了空格