Ste*_*eve 7 c++ list-initialization c++17
在下面的代码中,两次赋值有什么区别吗?在这两种情况下,value.v 是否会被默认构造,而 x 会被初始化为 42?
struct S
{
std::vector<int> v;
int x = 42;
};
S value;
void foo()
{
value = S();
value = { };
}
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 13
S()并且S{}几乎在所有情况下都意味着相同的事情。但并非所有情况。
S不是类类型,同样的事情:值初始化。IfS是一个不是聚合的类类型,仍然主要意味着相同的事情:值初始化。除了以下情况:
struct X { X(std::initializer_list<int>); };
auto x1 = X(); // ill-formed
auto x2 = X{}; // ok, calls constructor
Run Code Online (Sandbox Code Playgroud)如果S是聚合,则S()是值初始化,但是S{}聚合初始化。即使这在很多时候也意味着同样的事情。但不是所有的时间。
示例 1:显式默认构造函数使聚合初始化格式错误
struct A { explicit A(int = 0); };
struct B { A a; };
B b; // OK
B b2 = B(); // OK
B b3{}; // error through trying to copy-list-initialize a = {}
Run Code Online (Sandbox Code Playgroud)
示例 2:某些上下文中的值初始化先进行零初始化
struct C { C() {} int i; };
struct D { C a; };
D d1{}; // d1.a.i is indeterminate
D d2 = D(); // d2.a.i is zero
Run Code Online (Sandbox Code Playgroud)
不过,在 OP 示例中,whileS是一个带有隐式定义的默认构造函数的聚合——这是一个有趣的例子。但在这里,有一个在语义与额外的零初始化没有变化,我们正在初始化x到42和默认构造v两种方式。
请注意,在 OP 中,这也会调用(并打算调用)移动赋值运算符S{}:
value = { };
Run Code Online (Sandbox Code Playgroud)
这也有可能完全调用不同的运算符,因为{}最终可能会在不同的赋值运算符重载中将“更好的”绑定到某个不同的参数。std::optional必须跳过一些钩子以确保opt = {}实际调用移动赋值运算符。