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

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

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

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


当前回答

接受答案中的解决方案有一个明显的缺点——在控件离开main()函数后调用单例的析构函数。当一些依赖对象被分配到main中时,可能真的会有问题。

我在尝试在Qt应用程序中引入Singleton时遇到了这个问题。我决定,我的所有设置对话框都必须是Singleton,并采用了上面的模式。不幸的是,Qt的主类QApplication被分配在主函数的堆栈上,当没有应用程序对象可用时,Qt禁止创建/销毁对话框。

这就是为什么我更喜欢堆分配的单件。我为所有单例提供了显式的init()和term()方法,并在main内部调用它们。因此,我可以完全控制单体创建/销毁的顺序,而且我保证无论是否有人调用getInstance(),都会创建单体。

其他回答

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

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

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

简单的单例类,这必须是你的头类文件

#ifndef SC_SINGLETON_CLASS_H
#define SC_SINGLETON_CLASS_H

class SingletonClass
{
    public:
        static SingletonClass* Instance()
        {
           static SingletonClass* instance = new SingletonClass();
           return instance;
        }

        void Relocate(int X, int Y, int Z);

    private:
        SingletonClass();
        ~SingletonClass();
};

#define sSingletonClass SingletonClass::Instance()

#endif

像这样访问单例:

sSingletonClass->Relocate(1, 2, 5);

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

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

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

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

class Singleton
{
private:
   Singleton();

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

它没有动态内存分配。