Given:
//C++17
#include <string>
struct Foo {
int i;
std::string str;
};
int main() {
Foo foo{1, std::string("Hello, world!")};
}
Can Foo::i
and Foo::str
be directly initialized from 1
and std::string(...)
instead of being copied into them, and explain why can/can't using C++17 standard(probably some code for testing purpose)?
If they can't, how many copies are required?
Aggregate initialization basically performs element-wise copy-initialization. So this:
struct Foo {
int i;
std::string str;
};
Foo foo{1, std::string("Hello, world!")};
does the same initializations as:
int i = 1;
std::string str = std::string("Hello, world!");
And we have a new rule in C++17 that says that:
If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [ Example:
T x = T(T(T()));
calls theT
default constructor to initializex
. — end example ]
which means that the second initialization must behave as if you'd written:
std::string str("Hello, world!");
That is, zero copies.
A nice demonstration of the new rule is the following example:
struct X {
X(int ) { }
X(X&& ) = delete;
};
struct Y {
X x;
};
int main() {
Y y{X{4}}; // ill-formed in C++14 due to deleted move ctor
// ok in C++17, no move required
}