首页 > 解决方案 > Zero initialization of nested struct - compiler bug?

问题描述

Consider this example:

#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?");
}

If I understand correctly, according to https://en.cppreference.com/w/cpp/language/zero_initialization, it cannot throw because zero initialization should be performed for B::a as it should for "members of value-initialized class types that have no constructors".

If it throws, is it a compiler bug or am I missing something?

[edit]

Here with clang 10 and optimization enabled it just does "mov eax, 2" and "ret" (meaning the condition is false): https://godbolt.org/z/CXrc3G

But if I remove the braces, it does "mov eax, 1" and "ret" (meaning the condition is true). But here I think it can return whatever it want because it's just UB. https://godbolt.org/z/tBvLzZ

So it seems clang thinks that with braces zero initialization must be performed.

Edit: I submitted a bug on intel's website: https://community.intel.com/t5/Intel-C-Compiler/Aggregate-initialization-bug-with-nested-struct/td-p/1178228

An intel person replied "I've reported this issue to our Developer." Poor developer, single-handedly supporting all icc development.

标签: c++c++14

解决方案


首先:对象b.a.a, b.a.b, b.a.c,b.a.d保证为零初始化。其中 forfloat被初始化为= 0;(不一定是所有位为零的表示)。

B b{};在某些情况下仅转换为零初始化(cppreference 页面有点误导)。

在 C++14 中:因为B是一个聚合,所以这是聚合初始化,每个成员都被初始化为一个空列表。所以A a;被初始化为 if A a{};。也是一个聚合,所以它的A每个元素都被初始化为一个空列表,对于内置类型是零初始化。

在 C++11 中,措辞不同(从空列表对聚合类进行列表初始化实际上并不认为是聚合初始化),但结果是相同的。

在 C++03 中,B b{}; 是一个语法错误,但B b = {};被允许,并且结果也将有问题的浮点数初始化为零。

在 C++98 中,规则不同,长话短说,B b = {};将调用默认构造函数,A其值未初始化。我们喜欢假装 C++98 初始化从未存在,但一些编译器甚至在 2010 年代仍坚持这些规则。


有了这个,可能会有一些关于是否保证零初始化的浮点数作为运算符的争论false​​,||请参阅将浮点数与零进行比较

该标准说“将零值、空指针值或空成员指针值转换为false”。这不是 100% 精确的,但 IMO 零初始化float应该算作“零值”。


推荐阅读