C++11核心语言能处理Singleton死引用吗

Does C++11 core language takes care of Singleton Dead Reference?

本文关键字:引用 Singleton 处理 核心 语言 C++11      更新时间:2023-10-16

我最近读了安德烈·亚历山德雷斯库的《现代C++设计》。阅读6。第章,我开始担心我们公司的单身人士。由于我们经验丰富的团队领导编写了核心帮助库,比如singleton等……我问他处理singleton的方式是否解决了死引用问题?如果他使用C核心语言给出的at_exit函数调用?

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

即使听起来很棒,我在网上也找不到任何能证实他的信息。所以请告诉我C++11是否处理了单身汉的死引用问题,如果是,请解释一下背后的黑暗魔法是什么?

假设您的团队领导正在讨论实现如下的单身汉:

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

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

允许实现在与允许实现在命名空间范围(3.6.2(中静态初始化具有静态或线程存储持续时间的变量相同的条件下,以静态或线程保存持续时间对其他块范围变量执行早期初始化。否则,在控件第一次通过其声明时初始化此类变量;这样的变量在其初始化完成时被认为是初始化的。如果初始化通过抛出异常退出,则初始化未完成,因此下次控件进入声明时将重试。如果在初始化变量时控件同时进入声明,则并发执行应等待初始化完成。

静态初始化只允许在常量的情况下进行,因此只要T没有constexpr构造函数,就不必担心(但请阅读3.6.2了解完整规则,以防出现与代码相关的边缘情况(。

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

具有静态存储持续时间的初始化对象(即其生存期(3.8(已开始的对象(的析构函数(12.4(是从main返回并调用std::exit(18.5(的结果。给定线程内具有线程存储持续时间初始化对象的解构函数是从该线程的初始函数返回并调用调用std::exit的线程。在任何具有静态存储持续时间的对象的析构函数启动之前,对该线程内具有线程存储持续时间所有初始化对象的析构函数的完成进行排序。如果一个具有线程存储持续时间的对象的构造函数或动态初始化的完成顺序在另一个之前,则第二个的析构函数的完成顺序是在第一个析构函数启动之前。如果一个具有静态存储持续时间的对象的构造函数或动态初始化的完成顺序在另一个之前,则第二个的析构函数的完成顺序是在第一个析构函数启动之前。[注意:这个定义允许并发销毁。--结束注释]如果一个对象是静态初始化的,那么该对象的销毁顺序与该对象是动态初始化的顺序相同。对于数组或类类型的对象,在销毁在构造子对象期间初始化的具有静态存储持续时间的任何块作用域对象之前,将销毁该对象的所有子对象。如果通过异常退出对具有静态或线程存储持续时间的对象的销毁,则调用std::terminate(15.5.1(

虽然这一段给出了静态对象在并行构建时并发破坏的很大范围,但最重要的是,破坏的发生顺序与构建相反。

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