c ++模板在头文件中初始化单例静态指针

Nar*_*rek 3 c++ singleton templates static-members

头文件中的这个实现有什么问题?

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;
};
Run Code Online (Sandbox Code Playgroud)

我这样使用它:

typedef Singleton<MyClass> MyClassSingleton;
Run Code Online (Sandbox Code Playgroud)

我收到链接器错误:

error LNK2001: unresolved external symbol "private: static class MyClass * Singleton<class MyClass>::m_instance" (?m_instance@?$Singleton@VMyClass@@@@0PAVMyClass@@A)
Run Code Online (Sandbox Code Playgroud)

当我添加

template <typename T> T* Singleton<T>::m_instance = NULL;
Run Code Online (Sandbox Code Playgroud)

它有效,但我担心两件事:

  1. 静态成员应该在.cpp文件中定义,以便在所有编译单元中只有一个实例,即使您将头文件包含在10个源文件中
  2. 指针被标准初始化为NULL,为什么我需要显式初始化?

Pra*_*ian 10

您可以通过m_instance在类定义之后添加成员的定义来修复错误.

template<typename T>
T* Singleton<T>::m_instance = nullptr;
Run Code Online (Sandbox Code Playgroud)

对于类模板,可以static在标题本身中添加成员的定义,并且不会导致ODR违规.

但是,正如其他人所建议的那样,最好将你的getInstance()定义改为

static T& getInstance() 
{
    static T instance;
    return instance;
}
Run Code Online (Sandbox Code Playgroud)

C++ 11甚至保证函数局部static变量的创建instance是线程安全的.

  • 由于编译器处理模板的方式,类模板的静态数据成员可以在头文件本身中定义.它将它们标记为*弱符号*,并且链接器假定重复的符号相同并选择一个.对于非模板不是这样,链接器在看到重复定义时会出错. (2认同)