最近,我遇到了C++的Singleton设计模式的实现/实现。它看起来是这样的(我采用了现实生活中的例子):

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

从这个声明中,我可以推断实例字段是在堆上启动的。这意味着存在内存分配。对我来说完全不清楚的是,内存将在何时被释放?或者是否存在错误和内存泄漏?似乎在实现方面存在问题。

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


当前回答

#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);

其他回答

这里是一个使用CRTP的可模拟单例。它依赖于一个小助手在任何时候(最多)强制执行一个对象。要在程序执行过程中强制执行单个对象,请删除重置(我们发现这对测试很有用)。

ConcreteSinleton可以这样实现:

class ConcreteSingleton : public Singleton<ConcreteSingleton>
{
public:
  ConcreteSingleton(const Singleton<ConcreteSingleton>::PrivatePass&)
      : Singleton<StandardPaths>::Singleton{pass}
  {}
  
  // ... concrete interface
  int f() const {return 42;}

};

然后与一起使用

ConcreteSingleton::instance().f();

这是关于对象生命周期管理的。假设您的软件中有多个单体。它们依赖于Logger单例。在应用程序销毁期间,假设另一个单例对象使用Logger记录其销毁步骤。您必须保证Logger应该最后清理。因此,请同时查看本文:http://www.cs.wustl.edu/~schmidt/PDF/ObjMan.PDF

另一个非分配的选择:根据需要创建一个单例,比如C类:

singleton<C>()

使用

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

在当前C++中,这一点和Cætælin的答案都不是自动线程安全的,而是在C++0x中。

它确实可能是从堆中分配的,但没有源就无从得知。

典型的实现(取自我在emacs中已有的一些代码)是:

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

……然后依靠超出范围的程序进行清理。

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

这样做的另一个问题是它不是线程安全的。在多线程环境中,两个线程可以通过“if”,然后任何一个线程都有机会分配新实例(所以两者都会)。如果你依靠程序终止来清理,这仍然不是什么大问题。

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

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

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

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

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