考虑这个例子:
#include <vector>
#include <stdexcept>
struct A
{
float a;
float b;
float c;
float d;
};
struct B
{
A a;
std::vector<int> b;
};
int main() {
B b{};
if (b.a.a || b.a.b || b.a.c || b.a.d) throw std::runtime_error("Compiler bug?");
}
如果我没理解错的话,根据https://en.cppreference.com/w/cpp/language/zero_initialization ,它不能抛出,因为应该为 B::a 执行零初始化,因为它应该为“没有构造函数的值初始化类类型的成员”。
如果它抛出,是编译器错误还是我遗漏了什么?
[编辑]
这里使用 clang 10 并启用优化,它只执行“mov eax, 2”和“ret”(意味着条件为假): https://godbolt.org/z/CXrc3G
但是如果我去掉大括号,它会执行“mov eax, 1”和“ret”(意味着条件为真)。但在这里我认为它可以返回任何它想要的东西,因为它只是 UB。 https://godbolt.org/z/tBvLzZ
所以 clang 似乎认为必须执行大括号零初始化。
编辑:我在英特尔网站上提交了一个错误: https://community.intel.com/t5/Intel-C-Compiler/Aggregate-initialization-bug-with-nested-struct/td-p/1178228
一位情报人员回答说“我已经向我们的开发人员报告了这个问题。”可怜的开发者,一手支撑所有icc开发。
最佳答案
首先:对象 b.a.a
、b.a.b
、b.a.c
、b.a.d
保证被零初始化。 float
的初始化就好像 = 0;
(不一定是所有位都为零的表示)。
B b{};
在某些情况下仅转换为零初始化(cppreference 页面有点误导)。
在 C++14 中:由于 B
是一个 aggregate ,这是聚合初始化,每个成员都被初始化为一个空列表。所以 A a;
就像 A a{};
一样被初始化。 A
也是一个聚合,因此它的每个元素都被初始化为一个空列表,对于内置类型来说是零初始化。
在 C++11 中,措辞不同(从空列表对聚合类的列表初始化实际上不被视为聚合初始化)但结果是相同的。
在 C++03 中,B b{}
;是一个语法错误,但是 B b = {};
是允许的,而且结果是对有问题的 float 进行了零初始化。
在 C++98 中,规则不同,长话短说,B b = {};
会调用 A
的默认构造函数未初始化的值。我们喜欢假装 C++98 初始化从未存在过,但一些编译器甚至在 2010 年代仍坚持这些规则。
除此之外,对于 ||
运算符,零初始化 float 是否保证充当 false
可能存在一些争论,请参阅 Comparing floating point number to zero .
标准说“零值、空指针值或空成员指针值被转换为 false
”。这不是 100% 精确,但 IMO 零初始化的 float
应该算作此目的的“零值”。
关于c++ - 嵌套结构的零初始化 - 编译器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61603820/