【问题标题】:Destruction order of statically initialized, non-literal objects静态初始化的非文字对象的破坏顺序
【发布时间】:2014-11-29 00:09:56
【问题描述】:

recent question 让我注意到constexpr has changed in C++14 的方式。新特性是具有静态存储持续时间的非局部变量可以在静态初始化阶段进行初始化,如果其初始化程序由 constexpr 构造函数组成,即使该变量的类型不是文字类型。更准确地说,[basic.start.init] 中的新措辞是:

对象o 的常量初始化器 是一个常量表达式,除了它还可以为o 及其子对象调用constexpr 构造函数,即使这些对象不是-literal 类类型 [注意:这样的类可能有一个不平凡的析构函数——尾注]。 常量初始化如果具有静态或线程存储持续时间的对象由构造函数调用初始化,并且如果初始化完整表达式是对象的常量初始化器 [...],则执行常量初始化 [...] ]

典型的例子是std::unique_ptr,“不应该比手写更糟糕”:

std::unique_ptr<int> p;   // statically initialized by [unique.ptr.single.ctor],
                          // requires no code excution
int main()
{
    p = std::make_unique<int>(100);
}

// p is destroyed eventually

在此添加之前,静态初始化的变量要么是引用类型,要么是文字对象类型,因此具有微不足道的析构函数。但是现在静态初始化的全局变量可以有一个非平凡的析构函数。

相对于动态初始化的全局对象的析构函数,相对于其他静态初始化的析构函数,这样的析构函数调用是如何排序的?析构函数调用是如何排序的?

【问题讨论】:

  • 这对 C++14 来说并不新鲜;甚至先前的措辞也允许这样做。 (例如,std::mutex 有一个 constexpr 构造函数,因此它可以利用静态初始化。)
  • @T.C.:感谢您的澄清!

标签: c++ language-lawyer c++14 termination static-initialization


【解决方案1】:

考虑

如果一个对象是静态初始化的,那么该对象在 与对象被动态初始化的顺序相同。

和

如果完成构造函数或动态初始化一个 具有静态存储持续时间的对象在 另,第二个的析构函数的完成是有序的 在第一个析构函数启动之前。

现在,

静态初始化应在任何动态之前执行 初始化发生。

显然这回答了第一个问题:由于p 保证在执行任何动态初始化之前被初始化,因此在销毁任何动态初始化的对象之后调用析构函数。

本质上第二个问题,即几个静态初始化变量的破坏顺序,被简化为这些变量的初始化顺序:

使用静态存储动态初始化非局部变量 持续时间是有序的或无序的。显式的定义 专门的类模板静态数据成员已订购 初始化。其他类模板静态数据成员(即, 隐式或显式实例化的特化)具有无序 初始化。 其他具有静态存储的非局部变量 duration 已排序初始化。

粗体句包括所有不是实例化类的静态数据成员的静态初始化对象。它们在一个翻译单元中排序:

在单个变量中定义了有序初始化的变量 翻译单元应按其顺序初始化 翻译单元中的定义。

所以,总结一下:

  • 作为静态初始化对象且不是实例化类的静态数据成员的变量将按翻译文件中定义的相反顺序销毁。

  • ...在任何动态初始化的对象被销毁后,这些变量总是被销毁。

然而,尽管可能存在争论错误,但 Clang 和 GCC 目前似乎都没有以这种方式实现它:Demo。

【讨论】:

  • 这是来自 C++14 (FD)IS 吗?
  • @KerrekSB N4140,显然只包含编辑更改。让我检查是否符合最新草案。
  • @KerrekSB(或者,提供指向我应该引用的文档的链接并检查这些引用)
  • 是的,没错,它在 N4140 中。奇怪的是,粗体字似乎有disappeared from head。多么尴尬,我的整个问题都基于错误的文件。谢谢!
【解决方案2】:

[basic.start.term]/1 (N4140) 说:

如果对象是静态初始化的,则对象的销毁顺序与动态初始化对象的顺序相同。

据我了解,这意味着为了确定销毁顺序,所有静态初始化都被视为动态(有序或无序),并且以与此初始化相反的顺序调用析构函数。

【讨论】:

  • 是的,没错,但是对于动态初始化,有一组规则用于排序(有序与无序)。鉴于此规则,静态初始化的对象如何适应该排序?
  • 你看,它说“在单个翻译单元中定义的有序初始化的变量应按其定义的顺序进行初始化”。但这只有在命令初始化开始时才有帮助,而静态初始化变量则不然。
  • @KerrekSB 我认为这很清楚(更新了我的答案),但老实说,我还没有测试这是否真的像我认为的当前编译器那样有效
  • @Anton 你从哪里引用?有时文件很重要。
  • @remyabel N4140,但在 N3337 中是一样的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
相关资源
最近更新 更多