c++ - C++11 核心语言是否处理 Singleton Dead Reference?

标签 c++ c++11 singleton

我最近阅读了 Andrei Alexandrescu 的现代 C++ 设计。看完第六章,我开始担心我们公司的单例。由于我们经验丰富的团队负责人编写了核心帮助程序库,例如单例等...。我问他处理单例的方式是否解决了死引用问题?如果他使用C核心语言给出的at_exit函数调用呢?

他告诉我C++11支持单例,会连续执行CTOR和DTOR,不会有死引用问题。用户将不必处理同步。

虽然听起来很棒,但我在互联网上找不到任何可以证实他的信息。所以请告诉我 C++11 是否解决了单例的死引用问题,如果是的话请解释一下背后有什么黑魔法?

最佳答案

大概您的团队负责人正在谈论如下实现的单例:

T &get_value() {
   static T val;
   return val; 
}

在这种情况下,标准给出了两个保证。第一个是 val 对象将被构造一次,即程序执行流第一次通过局部静态变量的声明,即使这在多个线程上同时发生 6.7/4:

An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

静态初始化仅在常量情况下才允许,因此只要 T 没有 constexpr 构造函数,您就不必担心(但请阅读 3.6 .2 获取完整规则,以防出现与您的代码相关的边缘情况)。

第二个保证是所有具有静态存储持续时间的变量都将按照构造时的相反顺序销毁3.6.3/1:

Destructors (12.4) for initialized objects (that is, objects whose lifetime (3.8) has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit (18.5). Destructors for initialized objects with thread storage duration within a given thread are called as a result of returning from the initial function of that thread and as a result of that thread calling std::exit. The completions of the destructors for all initialized objects with thread storage duration within that thread are sequenced before the initiation of the destructors of any object with static storage duration. If the completion of the constructor or dynamic initialization of an object with thread storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. [Note: This definition permits concurrent destruction. — end note ] If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized. For an object of array or class type, all subobjects of that object are destroyed before any block-scope object with static storage duration initialized during the construction of the subobjects is destroyed. If the destruction of an object with static or thread storage duration exits via an exception, std::terminate is called (15.5.1).

虽然本段为静态对象并发构建时的并发销毁提供了很多范围,但要摆脱的主要问题是销毁以与构建相反的顺序发生。

总而言之,这意味着如果 T val 依赖于另一个单例函数中的某些 U val,则 U val 将始终在 T val 之前构造并在 T val 之后析构,所以总的来说,这是实现单例的安全方法(除非你正在做一些非常疯狂的事情)。

关于c++ - C++11 核心语言是否处理 Singleton Dead Reference?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23842433/

相关文章:

c++ - 为什么每次递归后我的变量都没有增加?

c++ - gcc 4.7 和递归 constexpr 函数

android - 将来自多个类的数据存储在中心对象中

c++ - 任务栏上的 GLFW 加载状态

c++ - 静态常量类成员作为成员数组的初始值设定项

c++ - 使 std::compare 函数成为一元的简单方法

Java内存泄漏理解

c++ - 静态函数强制单例模式?

c++ - 在类外部初始化的 constexpr 静态成员的声明中是否需要 constexpr 说明符?

C++ - 在后台 POSIX 线程上以固定增量时间循环