是否保证使用 {} 语法将 float 成员初始化为零?
Is a float member guaranteed to be zero initialized with {} syntax?
在C++17中,考虑这样一种情况,其中S
是一个删除了默认构造函数和float成员的结构,当S用空大括号初始化时,标准保证的float成员是被零初始化?
struct A {
int x{};
};
struct S
{
S() = delete;
A a;
float b;
};
int main()
{
auto s = S{}; // Is s.b guaranteed to be zero?
}
在我看来,cppreference.com不清楚,说两句:
If the number of initializer clauses is less than the number of members and basesor initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
(from here),这意味着 b 保证为零
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
这意味着 b 不能保证为零。
还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器无论如何都会进行零初始化:
The standard specifies that zero-initialization is not performed when the class has a user-provided or deleted default constructor, even if that default constructor is not selected by overload resolution. All known compilers performs additional zero-initialization if a non-deleted defaulted default constructor is selected.
与相关
这是 C++ 的怪癖 fixed in C++20。同时,您可以将 explicit
添加到已删除的默认构造函数以强制结构变为非聚合,并使您的代码有保证的编译错误:
struct A {
int x{};
};
struct S
{
explicit S() = delete;
const A a;
const float b;
};
int main()
{
auto s = S{}; // error: call to deleted constructor of 'S'
}
因为S
是聚合,所以S{}
会进行聚合初始化。当列表中没有初始化器时,标准中关于如何初始化成员的规则是 basically what you cited:
- If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
- Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
所以对于 b,这相当于 float b = {};
。根据列表初始化规则,我们必须得到 all the way down to 3.10:
Otherwise, if the initializer list has no elements, the object is value-initialized.
而值初始化会将float
初始化为0。
在C++17中,考虑这样一种情况,其中S
是一个删除了默认构造函数和float成员的结构,当S用空大括号初始化时,标准保证的float成员是被零初始化?
struct A {
int x{};
};
struct S
{
S() = delete;
A a;
float b;
};
int main()
{
auto s = S{}; // Is s.b guaranteed to be zero?
}
在我看来,cppreference.com不清楚,说两句:
If the number of initializer clauses is less than the number of members and basesor initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
(from here),这意味着 b 保证为零
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
这意味着 b 不能保证为零。
还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器无论如何都会进行零初始化:
The standard specifies that zero-initialization is not performed when the class has a user-provided or deleted default constructor, even if that default constructor is not selected by overload resolution. All known compilers performs additional zero-initialization if a non-deleted defaulted default constructor is selected.
与
这是 C++ 的怪癖 fixed in C++20。同时,您可以将 explicit
添加到已删除的默认构造函数以强制结构变为非聚合,并使您的代码有保证的编译错误:
struct A {
int x{};
};
struct S
{
explicit S() = delete;
const A a;
const float b;
};
int main()
{
auto s = S{}; // error: call to deleted constructor of 'S'
}
因为S
是聚合,所以S{}
会进行聚合初始化。当列表中没有初始化器时,标准中关于如何初始化成员的规则是 basically what you cited:
- If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
- Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
所以对于 b,这相当于 float b = {};
。根据列表初始化规则,我们必须得到 all the way down to 3.10:
Otherwise, if the initializer list has no elements, the object is value-initialized.
而值初始化会将float
初始化为0。