单例类实现版本

时间:2012-01-23 07:38:08

标签: c++ design-patterns singleton

我想讨论众所周知的Singleton设计模式的实施细微差别。 这里有两个C ++实现:

http://www.codeproject.com/Articles/1921/Singleton-Pattern-its-implementation-with-C

另一个是:

#ifndef __SINGLETON_HPP_
#define __SINGLETON_HPP_

template <class T>
class Singleton
{
public:
  static T* Instance() {
      if(!m_pInstance) m_pInstance = new T;
      assert(m_pInstance !=NULL);
      return m_pInstance;
  }
protected:
  Singleton();
  ~Singleton();
private:
  Singleton(Singleton const&);
  Singleton& operator=(Singleton const&);
  static T* m_pInstance;
};

template <class T> T* Singleton<T>::m_pInstance=NULL;

#endif

如果我们比较这个版本它们有哪些优点和缺点,最终是哪个版本?

2 个答案:

答案 0 :(得分:1)

这两个实现之间的主要区别是:

  • 第一个添加一个冗余标志来告诉你指针是否为空,因此占用的内存比它需要的多一点;
  • 第二个根本不是单身人士:没有任何东西阻止T拥有公共构造函数,从而打破了单例限制。

两者的主要问题(除了单身从不是一个好主意的事实之外)是:

  • 构造不是线程安全的;从两个线程调用Instance()可能会导致创建两个对象;
  • 泄漏记忆;他们使用new动态创建对象,但从不调用delete

在C ++中,很难安全地管理全局可访问对象的生命周期;出于这个原因(和many others),我建议完全避免使用Singleton反模式。在管理良好的范围内创建对象,并在需要时传递引用。

如果您真的想要一个全局可访问的实例,那么在大多数情况下,最简单和最安全的选项是:

static Singleton & Instance() {
    static Singleton instance;
    return instance;
}

这将在第一次调用函数时创建,C ++ 11编译器必须确保这是线程安全的。剩下的问题是实例可能在其他静态对象之前被销毁,如果它们的析构函数试图访问它就会导致灾难。

答案 1 :(得分:0)

基本上,两种实现都是相同的。 CodeProject上的实现提供了两件事:

  • 单身状态标志,允许您从外部将单身标记为“旧”(然后从内部正确地重新标记)
  • getInstance方法,从singleton的角度来看,这没什么特别的。然而,这使得代码在一段时间后对其他人和你自己更具可读性。

正好区别于 Cat::meow();
Cat::getInstance()->meow()