0

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?

Barry
  • 286,269
  • 29
  • 621
  • 977
JiaHao Xu
  • 2,452
  • 16
  • 31

1 Answers1

6

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 the T default constructor to initialize x. — 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
}
Barry
  • 286,269
  • 29
  • 621
  • 977