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

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

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

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


当前回答

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

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

class Singleton
{
private:
   Singleton();

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

它没有动态内存分配。

其他回答

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

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

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

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

我的实现与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;

以下是我对如何实现正确的单线图(以及其他非平凡静态对象)的看法:https://github.com/alex4747-pub/proper_singleton

摘要:

使用静态初始化列表在正确的时间实例化单线程:在进入main之后和启用多线程之前添加一些小的改进,使其对单元测试友好。

我没有在答案中找到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>