6

我希望以下代码会产生分段错误(或其他 UB):

struct T {
   T();
};

T t;
char const* str = "Test string";

T::T() {
   std::cout << str; // zero-initialised, only!
}

int main() {}

那是因为tstr. 由于零初始化,我希望str保持该值。(char const*)0我的解释[C++11: 3.6.2/2]支持这一点。

但是,上面的代码片段似乎按预期输出了字符串(我还通过打印指针的值来确认行为)。

是否有一些我在这里遗漏的静态初始化规则,允许在开始构建str之前进行值初始化?t它在标准中的什么位置?


在构建时出现在静态变量解析上,其中一个回答者断言使用char const*而不是std::string静态全局避免了静态初始化顺序惨败。我不同意,但现在我不太确定......

4

4 回答 4

6

str由常量表达式初始化并且const char *是 POD 类型(C++03 术语,但 C++11 是类似的,但具有不同的术语和更多允许的情况)。这样的初始化是在静态初始化阶段完成的,静态初始化阶段没有顺序问题。它发生在任何动态初始化之前。t动态初始化阶段初始化。

于 2012-01-05T22:00:48.723 回答
1

在正常意义上,内置类型根本没有初始化。通常,它们的初始内容直接从二进制文件的特殊区域进行内存映射,作为加载它的一部分。

于 2012-01-05T22:00:09.513 回答
1

我想我找到了;这里发生的不是内置类型,而是常量初始化器:

[C++11: 3.6.2/2]:具有静态存储持续时间 (3.7.1) 或线程存储持续时间 (3.7.2) 的变量应在任何其他初始化发生之前进行零初始化 (8.5)。

执行常量初始化

  • 如果出现在具有静态或线程存储持续时间的引用的初始化程序中的每个完整表达式(包括隐式转换)都是一个常量表达式(5.19)并且该引用绑定到一个左值,该左值指定具有静态存储持续时间的对象或临时(见 12.2);
  • 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果构造函数是constexpr构造函数,如果所有构造函数参数都是常量表达式(包括转换),并且如果在函数调用替换 (7.1.5) 之后,每个构造函数非静态数据成员的mem-initializers大括号或等号初始化器中的 call 和 full-expression是一个常量表达式;
  • 如果具有静态或线程存储持续时间的对象未由构造函数调用初始化,并且出现在其初始化程序中的每个完整表达式都是常量表达式。

零初始化和常量初始化合称为静态初始化;所有其他初始化都是动态初始化。静态初始化应在任何动态初始化发生之前执行。[..]

最后一句似乎会覆盖后续的排序规则,从而使此排序适用于翻译单元。

于 2012-01-05T22:01:48.677 回答
0
char const* str = "Test string";

由编译器/链接器完成,因此在程序开始运行之前它就处于“初始化状态”。

于 2012-01-05T22:01:42.373 回答