【问题标题】:Explanation of C++ singleton codeC++单例代码解释
【发布时间】:2013-10-14 19:10:56
【问题描述】:

最近有人问我关于 c++ 中的单例设计模式。我不确切知道它的作用或需要它的时间,所以我尝试用谷歌搜索它。我主要在 stackoverlow 上找到了很多答案,但我很难理解这些问题和答案中提到的代码。我知道单身人士应该满足以下属性,如果我错了,请纠正我。

It is used when we need to make one and only one instance of a class. 

这在我的脑海中提出了以下问题

Does this mean that it can be created only once or does this mean that it can be 
created many times but at a time only one copy can exist?

现在开始实施。 复制自here

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.
        // Don't forget to declare these two. You want to make sure they
        // are inaccessible otherwise you may accidentally get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement
};

请解释一下:

  1. 为什么我们必须将 getinstace() 函数设为静态?
  2. 为什么我们需要 S(S const&);构造函数?
  3. 什么是 void operator=(S const&);做什么?
  4. 为什么我们不实现最后两个函数?
  5. 为什么我们需要保证销毁此实例(如代码中所述)?

【问题讨论】:

    标签: c++ class design-patterns static singleton


    【解决方案1】:

    1) 是的。这个函数可以让你真正获得S 的一个实例。所以你打电话给S::getInstance()。如果它不是静态的,那么你将无法做到这一点。

    2、3 和 4) 请注意,构造函数和 operator= 是私有的。这是为了防止有人创建另一个S 实例,从而使单例状态无效。

    您应该使用S::getInstance() 来获取单个实例,而不是构建自己的S

    【讨论】:

      【解决方案2】:
      1. 是的,它应该是静态的,因为它不需要实例指针。让它成为非静态的将是徒劳的。

      2. 是的,我们确实需要至少一个函数式构造函数。需要以某种方式制作初始实例。创建第一个实例时,私有构造函数将强制外部用户通过getInstance 获取实例。

      3. 赋值运算符operator=(S const&) 用于为该实例分配新值。这对单例来说没有意义,因此被声明为私有并且没有实现。没有人可以使用它。

      4. 不,复制构造函数和赋值运算符必须是私有的并且没有实现。这是一个 C++ 习语,意思是:这个类不能被复制或分配给

      【讨论】:

        【解决方案3】:

        1.为什么我们必须将getinstace()函数设为静态?

        这是获取实例的唯一方法 - 静态意味着您不需要现有实例来调用它。如果您需要一个实例来获取一个实例,那么您将陷入鸡对蛋的局面。

        那是因为它是静态的,你可以写:

        S::getinstance().blah();
        

        如果不是静态的,你需要写

        S& s_instance = .... 
        s_instance.getInstance().blah();
        

        但是由于您已经有了一个实例,您不需要调用getInstance。如果获取实例的唯一方法是通过getInstance,您是如何获取该实例的?

        2.为什么需要S(S const&);构造函数?

        你没有。它是故意私有的并且没有实现,所以调用它会导致错误。 如果它没有显式设为私有且未实现,编译器将为您创建一个默认的公共复制构造函数......这意味着人们可以编写

        S scopy(S::getInstance());
        

        他们最终会得到一个新的 S 实例——打破单例语义。

        3.什么是void operator=(S const&);做什么?

        同2。它没有实现和私有,所以调用它会导致错误。同样,如果您没有明确说明,编译器将为您创建一个默认实例,在这种情况下,用户可以通过以下方式获得一个新实例。

        S scopy = S::getInstance();
        

        4.为什么我们不实现最后两个函数?

        如果您可以复制/分配单例,它将失去其单例状态。任何时候都应该只存在一个单例。

        但是请注意,单例通常被认为是反模式。没有非常充分理由你不想使用的东西。理解随之而来的线程问题也是明智之举……除此之外,还有一些静态初始化顺序惨败,您会遇到一些实现它的方法。 (您的代码中的方式还可以,但很容易出错。)

        【讨论】:

        • 您好,关于第 4 段中的问题?这是否意味着它只能创建一次,还是意味着它可以创建多次但一次只能存在一个副本?
        • 只会创建一次,第一次调用getInstance。但是你可以多次获得对它的引用。
        • 最后一件事,为什么我们需要保证销毁这个实例(如代码中所述)?单例的唯一要求不就是“它应该只有一个实例”,那么我们为什么要为它的释放而烦恼呢?
        • 单例通常用于管理重要的单实例资源(网络、数据库、文件系统等)。这些资源的清理通常在析构函数中完成。如果您的单例没有被销毁,那么这些可能无法正确清理 - 可能导致数据丢失、网络问题等。
        • 第3点所示的复制初始化是完全错误的,它将使用复制构造函数,而不是赋值。初始化不使用赋值运算符。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-24
        • 2014-11-14
        • 2018-10-04
        • 1970-01-01
        • 1970-01-01
        • 2011-06-25
        相关资源
        最近更新 更多