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

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

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

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


当前回答

我没有在答案中找到CRTP实现,所以这里是:

template<typename HeirT>
class Singleton
{
public:
    Singleton() = delete;

    Singleton(const Singleton &) = delete;

    Singleton &operator=(const Singleton &) = delete;

    static HeirT &instance()
    {
        static HeirT instance;
        return instance;
    }
};

要使用,只需从此继承类,例如:class Test:public Singleton<Test>

其他回答

作为单身汉,你通常不希望它被破坏。

当程序终止时,它将被拆除并释放,这是单例的正常行为。如果您希望能够显式地清理它,那么向类中添加一个静态方法非常容易,该方法允许您将其恢复到干净状态,并在下次使用时重新分配,但这超出了“经典”单例的范围。

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

我更喜欢这种实现(事实上,我更喜欢的说法并不正确,因为我尽可能避免单例):

class Singleton
{
private:
   Singleton();

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

它没有动态内存分配。

这里是一个使用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();

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

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

它将类的实例化限制为一个对象。当只需要一个对象来协调整个系统的操作时,这非常有用

class Singleton {
private:
    int data;
    static Singleton* instance;
    Singleton();
public:
    static Singleton* getInstance();
};
Singleton* Singleton::instance = 0;
Singleton::Singleton()
{
    this->data = 0;
    cout << "constructor called.." << endl;
}

 

Singleton* Singleton::getInstance() {
    if (!instance) {
        instance = new Singleton();
        return instance;
    }
}
int main() {
    Singleton *s = s->getInstance();
    Singleton *s1 =s1->getInstance();
    }