c++ - c++单例设计模式

  显示原文与译文双语对照的内容

最近我进入了 C++的Singleton设计模式的实现/实现。 它看起来像这个( 我从现实生活中采用了它):


//a lot of methods are omitted here
class Singleton
{
 public:
 static Singleton* getInstance( );
 ~Singleton( );
 private:
 Singleton( );
 static Singleton* instance;
};

从这个声明我可以推断实例字段是在堆上启动的。 这意味着有一个内存分配。 对于我来说完全不清楚的是,内存将被释放? 还是有 Bug 和内存泄漏? 在实现中似乎有问题。

我的主要问题是,如何以正确的方式实现它?

时间:

有保障的破坏为一个简单的设计对于一个懒惰 evaluated: singleton,参见本文
可以为我提供 C++ 中的Singleton示例

经典的懒惰评估和正确销毁的singleton 。


class S
{
 public:
 static S& getInstance()
 {
 static S instance;//Guaranteed to be destroyed.
//Instantiated on first use.
 return instance;
 }
 private:
 S() {};//Constructor? (the {} brackets) are needed here.

//C++ 03
//========
//Dont forget to declare these two. You want to make sure they
//are unacceptable otherwise you may accidentally get copies of
//your singleton appearing.
 S(S const&);//Don't Implement
 void operator=(S const&);//Don't implement

//C++ 11
//=======
//We can use the better technique of deleting the methods
//we don't want.
 S(S const&) = delete;
 void operator=(S const&) = delete;

};

有关什么时候使用singleton的文章,请参阅本文: ( 不经常)
Singleton: 如何使用它

请参阅这两篇关于初始化顺序和如何处理的文章:
静态变量初始化顺序
查找 C++ 静态初始化顺序问题

请参阅本文描述生存期:
C++ 函数中静态变量的生命周期

请看本文,讨论了一些对单例的影响:
单实例实例声明为GetInstance方法的静态变量

请看本文,解释为什么双重检查将无法在 C++ 上运行:
程序员应该知道的所有常见未定义行为

你可以避免内存分配。 有很多变体,在多线程环境下都有问题。

我喜欢这种实现( 实际上,我没有正确地说我喜欢,因为我尽可能避免单例):


class Singleton
{
private:
 Singleton();

public:
 static Singleton& instance()
 {
 static Singleton INSTANCE;
 return INSTANCE;
 }
};

它没有动态内存分配。

另一个non-allocating替代:创建一个单独的类,比如类 C,你需要它:

 
singleton<C>()

 

使用


template <class X>
X& singleton()
{
 static X x;
 return x;
}

如果要在堆中分配对象,为什么不使用自动指针。 内存也将被释放,因为我们正在使用自动指针。


class S
{
 public:
 static S& getInstance()
 {
 if( m_s.get() == 0 )
 {
 m_s.reset( new S() );
 }
 return *m_s;
 }

 private:
 static std::auto_ptr<S> m_s;

 S();
 S(S const&);//Don't Implement
 void operator=(S const&);//Don't implement
};

std::auto_ptr<S> S::m_s(0);

它确实是从堆中分配的,但是没有源,没有办法知道。

典型的实现( 从我在emacs中得到的一些代码获得) 是:


Singleton * Singleton::getInstance() {
 if (!instance) {
 instance = new Singleton();
 };
 return instance;
};

。并依靠程序超出范围后清理。

如果你在一个必须手动完成清理的平台上工作,我可能会添加手动清理例程。

这样做的另一个问题是它不是 thread-safe 。 在多线程环境中,两个线程可以在有机会分配新实例的情况下通过"中频"。 如果你依靠程序终止来清理,这仍然不是太大。


#define INS(c) private:void operator=(c const&){};public:static c& I(){static c _instance;return _instance;}

例如:


 class CCtrl
 {
 private:
 CCtrl(void);
 virtual ~CCtrl(void);

 public:
 INS(CCtrl);

...