使用指针和使用静态对象的Singleton实现之间的区别

时间:2012-10-24 10:38:43

标签: c++ design-patterns singleton

编辑:对不起,我的问题不明确,为什么书籍/文章更喜欢实施#1而不是实施#2?

使用指针实现Singleton类与使用静态对象相比有什么实际优势?为什么大多数书都喜欢这个

class Singleton
{
  private:

    static Singleton *p_inst;
    Singleton();

  public:

    static Singleton * instance()
    {
      if (!p_inst)
      {
        p_inst = new Singleton();
      }

      return p_inst;
    }
};

这个

class Singleton
{
  public:
    static Singleton& Instance()
    {
        static Singleton inst;
        return inst;
    }

  protected:
    Singleton(); // Prevent construction
    Singleton(const Singleton&); // Prevent construction by copying
    Singleton& operator=(const Singleton&); // Prevent assignment
    ~Singleton(); // Prevent unwanted destruction
};

7 个答案:

答案 0 :(得分:17)

  

为什么书籍/文章更喜欢实施#1而不是实施#2?

因为大多数描述Singleton反模式的文章在尝试在C ++中安全地实现它时并不完全理解所有隐藏的危险。要做到这一点非常困难。

  

使用指针实现Singleton类与使用静态对象相比有什么实际优势?

使用带有new但没有delete的指针可确保永远不会销毁该对象,因此在其生命周期结束后不存在访问它的危险。结合“懒惰”创建,第一次访问它,这可以保证所有访问都是有效的对象。缺点是创建不是线程安全的,并且在程序结束时不会释放它获取的对象和任何资源。

使用本地静态对象,在任何支持C ++ 11线程模型的编译器上创建都是线程安全的。此外,该对象将在程序结束时被销毁。但是,可以在破坏后访问对象(例如从另一个静态对象的析构函数),这可能会导致令人讨厌的错误。

最佳选择是尽可能避免静态数据和全局可访问数据。特别是,永远不要使用Singleton反模式;它将全局静态数据与奇怪的实例化限制相结合,使测试变得不必要。

答案 1 :(得分:8)

第二个版本(使用本地静态变量)具有显着的优势。

它不需要使用免费存储,因此不会被检测为内存泄漏。它是线程安全的(在C++11中)。它更短更简单。

唯一的缺点是它不可能使其成为线程安全(对于前C ++ 11编译器),并且它不会为您提供显式销毁单例实例的选项。

答案 2 :(得分:4)

总是更喜欢第二个,但第一个确实有一些潜在的有趣优势: -

  • 清晰度 - 指针检查为空是有效的 构造静态时编译器在底层做了什么 对象。从“学习”的角度来看,它具有指导意义 了解在方法中使用静态对象时发生的情况 范围。

  • 延迟分配 - 在第一种情况下,Singleton对象是 堆分配。如果您的函数永远不会运行,则该对象永远不会 构建,永远不会消耗记忆。但是,在第二种情况下, 内存由链接器分配,用于在之前保存对象 程序启动,即使“构造”是懒惰的。

答案 3 :(得分:3)

第二个具有非确定性破坏。第一个,你可以控制何时删除指针,如果有的话。

第一个构造当然不是线程安全的,但可以使用boost::call_once(或std::call_once如果可用)来实现

第二个结构很常见,许多编译器使它成为线程安全的,即使在技术上它不符合标准(尽管按照标准,对象应该只创建一次,我不确定标准的视图在另一个线程使用它之前完成构造。)

如果破坏顺序没有问题,那么你可以继续使用静态版本,只要你的编译器保证它是线程安全的。

答案 4 :(得分:2)

第二个例子名为“Meyers'Singleton”,因为它首先在“Effective C ++”或“More Effective C ++”中发布。我不确定是哪一个,但两者都是在“设计模式”之后发布的 - 所以四人帮也可能在他们的书写完时没有意识到第二种模式。

此外,第一种方法对于其他语言来说更为标准 - 你可以用Java或C#做第一种方法,但不能用第二种做法,所以来自不同背景的人可能是第一种更有名的人的另一个原因

在技术方面,使用第一种方法可以控制单身人士何时被摧毁,但这也会给你带来很多麻烦。

答案 5 :(得分:1)

一个优点是您不必检查单例是否已经实例化。

另一个原因是您不必担心取消分配任何内存。

答案 6 :(得分:-3)

非本地静态怎么样?有人看到这个问题吗?

class Singleton
{
    static Singleton singleton;
    Singleton();
    // etc

public:
    static Singleton &Instance() { return singleton; }
};

Singleton Singleton::singleton;

// etc