协慌网

登录 贡献 社区

C ++ Singleton 设计模式

最近,我碰到了 C ++ 的 Singleton 设计模式的实现 / 实现。它看起来像这样(我从实际示例中采用了它):

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

从该声明中,我可以推断出实例字段是在堆上初始化的。这意味着存在内存分配。对我来说,完全不清楚的是何时确切地将要释放内存?还是有错误和内存泄漏?似乎实现有问题。

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

答案

在 2008 年,我提供了 Singleton 设计模式的 C ++ 98 实现,该模式是惰性评估的,保证销毁的,技术上不是线程安全的:
任何人都可以为我提供 c ++ 中的 Singleton 示例吗?

这是 Singleton 设计模式的更新的 C ++ 11 实现,该模式是延迟评估,正确销毁和线程安全的

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {}                    // Constructor? (the {} brackets) are needed here.

        // C++ 03
        // ========
        // Don't forget to declare these two. You want to make sure they
        // are inaccessible(especially from outside), otherwise, you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement

        // C++ 11
        // =======
        // We can use the better technique of deleting the methods
        // we don't want.
    public:
        S(S const&)               = delete;
        void operator=(S const&)  = delete;

        // Note: Scott Meyers mentions in his Effective Modern
        //       C++ book, that deleted functions should generally
        //       be public as it results in better error messages
        //       due to the compilers behavior to check accessibility
        //       before deleted status
};

有关何时使用单例的信息,请参见此文章:(不常使用)
Singleton:应如何使用

请参阅这两篇有关初始化顺序以及如何应对的文章:
静态变量初始化顺序
查找 C ++ 静态初始化顺序问题

请参阅描述寿命的文章:
C ++ 函数中静态变量的生存期是多少?

请参阅本文,讨论对单例的一些线程含义:
声明为 GetInstance 方法的静态变量的 Singleton 实例,它是线程安全的吗?

请参阅本文,该文章解释了为什么双重检查锁定在 C ++ 上不起作用:
C ++ 程序员应该知道哪些常见的未定义行为?
Dobbs 博士:C ++ 和双重检查锁定的风险:第一部分

作为单例,您通常不希望其被破坏。

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

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

我更喜欢这种实现方式(实际上,我没有正确说出我喜欢的方式,因为我尽可能避免单例):

class Singleton
{
private:
   Singleton();

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

它没有动态内存分配。