静态存储持续时间初始化

Static-storage-duration initialization

本文关键字:初始化 持续时间 存储 静态      更新时间:2023-10-16

C++静态存储持续时间对象以未指定的顺序初始化(同一编译单元除外)。

使用如下代码:

#include <iostream>
struct Foo {
Foo() {
std::cout << "Hello, world.n";
}
} foo_instance;
int main(int argc, const char *argv[]) {
return 0;
}

在标准中哪里说我已经可以在foo_instance初始化期间使用std::cout

我知道我可以通过在<iostream>中添加一些技巧来确保事情会起作用,例如让它包含类似的东西

int __ensure_stdout_initialization_call();
namespace {
int __ensure_stdout_initialization
= __ensure_stdout_initialization_call();
}

然而,问题是在哪里保证对标准库所需的所有初始化都这样做。

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

无论标准中标准流初始化如何,唯一的要求是

27.4.1 概述 [iostream.objects.overview]

3 在构造类ios_base::Init的对象之前或期间的某个时间构造对象和建立关联,并且在任何情况下都位于 main 主体开始执行之前。 291 在程序執行期間不會摧毀物件。 292 在翻译单元中包括<iostream>的结果应<iostream>定义具有静态存储持续时间的ios_base::Init实例。

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

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

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

因此,ios_base::Init将在变量和标准流准备就绪之前初始化,但是如果您在包含变量之前声明变量,似乎仍然可以<iostream>开枪:

struct Foo
{
Foo();
} foo_instance; // uses ::std::cout
#include <iostream> // declares ios_base::Init variable that will init ::std::cout
Foo::Foo()
{
std::cout << "Hello, world.n";
}
int main(int argc, const char *argv[]) {
return 0;
}

死亡示例

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

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

基本思想是在头文件中包含一个帮助程序静态对象,在初始化期间,检查流对象是否已初始化,如果没有,则对其进行初始化。通常包括首先出现,此类帮助程序静态对象在同一转换单元中的任何其他静态对象之前初始化,并确保在任何其他静态对象引用流对象之前正确初始化它。

(*)编辑:

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

27.4 标准 iostream 对象

27.4.1.2

构建对象并在 类对象之前或期间的某个时间 ios_base::Init 是构造的,并且在任何情况下在主体之前 开始执行。在程序期间不会销毁对象 执行。在翻译单元中包含的结果 应好像定义了 ios_base::Init 的实例 静态存储持续时间。同样,整个程序的行为应为 如果至少有一个 ios_base::Init 的静态实例 存储持续时间。

看看标题<iostream>

该标准说它的行为就像它定义了一个类型为std::ios_base::Init的TU本地对象,它处理初始化并在最后刷新标准流。