2

我通常以这种方式实现单例模式:

class Singleton
{
    public:
        virtual ~Singleton() {}

        static Singleton& GetInstance()
        {
            static Singleton instance;
            return instance;
        }

    private:
        Singleton();
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);
}

最近,我遇到了这个实现,它略有不同:

class Singleton
{
    public:
        Singleton();
        virtual ~Singleton() {}

        static Singleton& GetInstance()
        {
            return instance;
        }

    private:
        Singleton(const Singleton&);
        Singleton& operator=(const Singleton&);

        static Singleton instance;
}

Singleton Singleton::instance;

哪个实施更好?

不将构造函数设为私有(第二次实现)不是很危险吗?

谢谢。

4

5 回答 5

4

它们是有区别的。在第一种情况下instance,在第一次调用函数时初始化。在第二种情况下,它在程序启动时被初始化。

如果您创建一个public构造函数 - 它不是 a singleton,因为它可以由任何人创建

于 2012-07-20T13:36:20.167 回答
4

我不需要重复其他答案中关于懒惰构造单例的好处。

让我补充一下:

public:
    Singleton();
    virtual ~Singleton() {}

这个特定类的设计者觉得有必要允许:

  • 从这个Singleton类派生,说派生类被称为DerSingleton
  • DerSingleton可以有可以用指针删除的实例Singleton(所以DerSingleton不是单例)

的任何实例DerSingleton也是Singleton定义的实例,因此可以得出,如果DerSingleton被实例化,Singleton则不是单例。

所以这个设计断言了两件事:

  • 这个类是一个单例
  • 这个类不是单例
于 2012-07-20T14:13:30.523 回答
3

如果您在另一个命名空间级别变量或类静态成员的初始化期间尝试使用单例,则会出现主要的行为差异。在第一种情况下,由于实际对象是在第一次函数调用期间按需创建的,因此构造期间的行为将得到很好的定义。在第二种情况下,所有的赌注都被取消了,因为来自不同翻译单元的静态对象初始化的相对顺序是未定义的。

另请注意,虽然第一个在施工期间是安全的,但在破坏期间可能不是。也就是说,如果具有静态存储持续时间的对象在构造过程中不使用单例,则可以在单例实例之前对其进行初始化。销毁的顺序与构造的顺序相反,在这种特殊情况下,单例将在另一个对象之前被销毁。如果该对象在其析构函数中使用单例,它将导致未定义的行为。

于 2012-07-20T13:45:53.857 回答
1

第二种实现是错误的。默认构造函数应该是私有的。事实上,它本身并不是一个单例。除此之外,@Andrew 和@Brady 的答案中提到了实现之间的差异。

于 2012-07-20T13:40:19.333 回答
0

两者之间的一个重要区别是第二个示例中实例的创建是线程安全的。

你是绝对正确的,构造函数应该是私有的。

这是一个相关的问题:https ://stackoverflow.com/a/10479084/1158895

于 2012-07-20T13:40:53.610 回答