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

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

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

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


当前回答

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

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

其他回答

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

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

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

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

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

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

@洛基·阿斯塔里的回答很好。

然而,有时使用多个静态对象时,您需要能够保证在所有使用单例的静态对象不再需要它之前,单例不会被破坏。

在这种情况下,std::shared_ptr可用于保持所有用户的单例有效,即使在程序结束时调用静态析构函数:

class Singleton
{
public:
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    static std::shared_ptr<Singleton> instance()
    {
        static std::shared_ptr<Singleton> s{new Singleton};
        return s;
    }

private:
    Singleton() {}
};

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

singleton<C>()

使用

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

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

我的实现与Galik的类似。不同的是,我的实现允许共享指针清理分配的内存,而不是在应用程序退出并清理静态指针之前保留内存。

#pragma once

#include <memory>

template<typename T>
class Singleton
{
private:
  static std::weak_ptr<T> _singleton;
public:
  static std::shared_ptr<T> singleton()
  {
    std::shared_ptr<T> singleton = _singleton.lock();
    if (!singleton) 
    {
      singleton.reset(new T());
      _singleton = singleton;
    }

    return singleton;
  }
};

template<typename T>
std::weak_ptr<T> Singleton<T>::_singleton;

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