【问题标题】:Static local variable in C++11?C ++ 11中的静态局部变量?
【发布时间】:2016-04-24 12:06:58
【问题描述】:

有什么区别:

class A {
 public:
   static const A& GetInstance() {
     static A a;
     return a;
   }
};

class B {
  public:
   static const B* GetInstance() {
     static B* b = new B;
     return b;
   }
};

? A 和 B 之间的 Singleton 的生命周期是否存在差异?对象的内存位置?一般有什么区别吗?

【问题讨论】:

    标签: c++ c++11 static singleton


    【解决方案1】:

    这两种情况下对象的生命周期是不同的。 C++ 保证静态局部对象将以与其构造相反的顺序被销毁。在这两种情况下,都会在首次​​调用 GetInstance 时进行构造。

    但是,在第二种情况下,变量b 被分配了一个分配有new 的指针。当b 从静态存储中删除时,该内存将一直保留到堆最终被拆除。在那个阶段,它将被视为“泄露”,并且永远不会调用B 的析构函数(如果有)。

    最好像这样实现基于指针的方法:

    class B {
      public:
       static const B* GetInstance() {
         static std::unique_ptr<B> b( new B );
         return b.get();
       }
    };
    

    现在,B::~B() 将被调用(如果适用),当b 被销毁时,该内存将被正确删除,并且生命周期与您的第一个示例相同。

    这只是留下您关于内存位置的问题。位置会有所不同。静态变量一般存储在程序的数据段中,而用new分配的任何东西都将存储在堆中。

    【讨论】:

    • 事后考虑,当AB 太大而无法分别放入堆或数据段时,程序行为也可能有所不同。如果B 太大,那么new B 应该抛出std::bad_alloc。在A 的情况下,我不确定是否抛出了可捕获的异常,或者程序是否会出现段错误并死掉。
    【解决方案2】:

    添加到第一个答案,2 cmets(假设您要创建一个单例)。

    1. 如果 2 个线程尝试访问重叠的静态实例,如果访问是第一次访问(在运行构造函数时),则会出现线程/争用问题。如今,C++ 具有编译器/标准支持,可以自动使这个静态单例初始化线程安全。
    2. 在堆的情况下,您不想每次都在堆上创建一个新实例。只需检查 nullptr,并且只在第一次在堆上创建实例。

    编辑:这是一个 SO 问题,其中答案包含与标准相关的参考:Heap/dynamic vs. static memory allocation for C++ singleton class instance

    【讨论】:

    • 如问题中所述,在 C++11 中,您提到的 (1) 和 (2) 均由编译器保证。 (1) 编译器保证static局部变量初始化是线程安全的。 (2) 编译器保证static局部变量初始化只会执行一次,所有后续对该函数的调用都会跳过静态局部变量的重新初始化(因此每次都不会创建新实例)。
    • @iBrAaAa ?该问题未提及该标准的任何保证。相关部分是 6.7.4,参见例如stackoverflow.com/questions/15062767/… 因此,使用函数静态变量意味着您可以从标准中获得同步方面的帮助..
    猜你喜欢
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 2015-10-04
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 2012-08-24
    相关资源
    最近更新 更多