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

时间:2014-05-15 23:36:48

标签: c++ templates singleton 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;
};

我这样用:

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;

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

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

5 个答案:

答案 0 :(得分:10)

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

template<typename T>
T* Singleton<T>::m_instance = nullptr;

对于类模板,可以在标题中添加static成员的定义,但不会导致ODR违规。

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

static T& getInstance() 
{
    static T instance;
    return instance;
}

C ++ 11甚至可以保证函数local static变量instance的创建是线程安全的。

答案 1 :(得分:3)

静态成员总是需要初始化一次,包括来自模板实例化的成员。

如果您真的喜欢,可以使用本地静态来避免这种情况:

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
};

答案 2 :(得分:2)

如果您真的想要使用单身,并且您确实想要使用模板化的单身,那么您可能想要使用Scott Meyer's singleton approach

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>&);
};

答案 3 :(得分:2)

  

指针被标准初始化为NULL,为什么我需要   明确初始化?

你不需要。

template <typename T>
T* Singleton<T>::m_instance;

这就足够静态&amp;全局变量默认为零初始化

具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应为零初始化(8.5) 在进行任何其他初始化之前。

答案 4 :(得分:0)

其他人已经回答了如何修复代码,但你的问题也是关于推理的。作为解释,你正在努力的是声明和定义之间的区别。在这一行:

static T* m_instance;

您声明m_instance有一个名称,但您尚未定义该空间。您添加的代码行定义了空格。