静态存储持续时间初始化

时间:2017-06-18 08:24:14

标签: c++ initialization language-lawyer iostream

在C ++中,static-storage-duration对象以未指定的顺序初始化(在同一编译单元中除外)。

代码如下:

#include <iostream>

struct Foo {
    Foo() {
        std::cout << "Hello, world.\n";
    }
} foo_instance;

int main(int argc, const char *argv[]) {
    return 0;
}

标准中说明的地方我在初始化std::cout期间已经可以使用foo_instance了吗?

我知道我可以通过在<iostream>中添加一些技巧来确保事情有效,例如让它包含类似

的内容
int __ensure_stdout_initialization_call();
namespace {
    int __ensure_stdout_initialization
      = __ensure_stdout_initialization_call();
}
然而,问题在于它是否能够保证标准库所需的所有初始化都能完成。

3 个答案:

答案 0 :(得分:2)

我不确定它是否在标准(*)中明确说明,但通常是 std :: cin std :: cout std: :cerr 是在Nifty Counter成语的帮助下实现的。

基本思想是在头文件中包含一个辅助静态对象,在初始化过程中,检查流对象是否已经初始化,如果不是,则初始化它。由于包含通常是第一个,因此在同一个转换单元中的任何其他静态对象之前初始化这样的辅助静态对象,并确保在任何其他静态对象引用它之前正确初始化流对象。

(*)编辑:

以下是标准草案 N3936 的适当措辞:

  

27.4标准iostream对象

     

27.4.1.2

     

构造对象并建立关联   在第一次上课之前或期间的某个时间   构造ios_base :: Init,无论如何都是在main的主体之前   开始执行。程序期间不会销毁对象   执行。结果包括&lt; iostream&gt;在翻译单位   应该好像定义了一个ios_base :: Init的实例   静态存储时间。同样,整个程序应表现为   如果至少有一个带静态的ios_base :: Init实例   储存期限。

答案 1 :(得分:2)

TL;博士;在初始化std::cout期间,您不应使用foo_instance

标准中标准流初始化的唯一要求是

  

27.4.1概述[iostream.objects.overview]

     

3构造对象并在第一次构造类ios_base::Init的对象之前或期间的某个时间建立关联,并且在主体开始执行之前的任何情况下都建立关联。 291在程序执行期间不会销毁对象。 292在翻译单元中包含<iostream>的结果应该好像<iostream>定义了具有静态存储持续时间的ios_base::Init实例。

因此,如果您在声明静态变量之前包含<iostream>,那么您将保存,因为根据标准

  

3.6.3非局部变量的动态初始化[basic.start.dynamic]

     

2具有静态存储持续时间的非局部变量V和W的动态初始化按如下顺序排序:   (2.1)如果V和W在单个转换单元中进行了有序初始化并且在W之前定义了V,则在初始化W之前对V的初始化进行排序。

所以ios_base::Init会在您的变量和标准流准备就绪之前进行初始化,但是如果您在之前声明变量包括{{{}},那么您似乎仍可以开始自我攻击。 1}}:

<iostream>

dying example

所以我可以得出结论,在非局部变量的动态初始化期间你不能使用std :: cout。

答案 2 :(得分:1)

查看标题<iostream>

该标准表示它的定义类似于std::ios_base::Init类型的TU本地对象,它处理初始化并最终刷新标准流。