In the code below, is there any difference between the two assignments to value? In both cases, would value.v be default constructed, and x be initialized to 42?
struct S
{
std::vector<int> v;
int x = 42;
};
S value;
void foo()
{
value = S();
value = { };
}
S()
and S{}
mean the same thing in nearly all cases. But not all cases.
S
is not a class type, same thing: value initialization. If S
is a class type that is not an aggregate, still mostly means the same thing: value initialization. Except in cases like:
struct X { X(std::initializer_list<int>); };
auto x1 = X(); // ill-formed
auto x2 = X{}; // ok, calls constructor
if S
is an aggregate, then S()
is value-initialization but S{}
s aggregate-initialization. Even that means the same thing a lot of the time. But not all of the time.
Example 1: explicit default constructor makes aggregate-initialization ill-formed
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 = {}
Example 2: value initialization in some contexts does zero-initialization first
struct C { C() {} int i; };
struct D { C a; };
D d1{}; // d1.a.i is indeterminate
D d2 = D(); // d2.a.i is zero
In the OP example though, while S
is an aggregate with an implicitly-defined default constructor - this is the interesting case. But here, there's no change in semantics with the extra zero-initialization, we're initializing x
to 42
and default-constructing v
either way.
Note that also while in OP, this invokes (and is intended to invoke) the move assignment operator from S{}
:
value = { };
it's also possible that this could invoke a different operator entirely, since {}
could end up binding "better" to some different parameter in a different assignment operator overload. std::optional
has to jump through some hooks to ensure that opt = {}
actually invokes the move assignment operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With