Lets say we have the following code:
#include <iostream>
#include <string>
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
std::string s;
};
struct B
{
A a;
};
int main()
{
B{A()};
}
Here, I believe struct A
is not an aggregate, as it has both non-trivial constructors and also a std::string
member which I presume is not an aggregate. This presumably means that B
is also not an aggregate.
Yet I can aggregate initialize B. In addition this can be done without either the copy nor move constructor being called (e.g. C++0x GCC 4.5.1 on ideone).
This behavior seems like a useful optimization, particularly for composing together large stack types that don't have cheap moves.
My question is: When is this sort of aggregate initialization valid under C++0x?
Edit + follow up question:
DeadMG below answered with the following:
That's not aggregate initialization at all, it's uniform initialization, which basically in this case means calling the constructor, and the no copy or move is probably done by RVO and NRVO.
Note that when I change B
to the following:
struct B
{
A a;
B(const A& a_) : a(a_) {}
B(A&& a_) : a(std::move(a_)) {}
};
A move is performed.
So if this is just uniform initialization and just calling the constructor and doing nothing special, then how do I write a constructor that allows the move to be elided?
Or is GCC just not eliding the move here when it is valid to do so, and if so, is there a compiler and optimization setting that will elide the move?
B
that takes the relevant parameters forA
so you can constructB::A
in B's initializer list, but what exactly is your concern? – Selfdeceptionstd::array
is intended as a simple aggregate type which has no custom constructors. Hence all its constructors are automatically generated, and a simplearray<int, 1000> newarray(move(oldarray))
should do the right thing (check the assembly yourself if you're unsure). – Selfdeceptionpublic
. Containing non-aggregate types is not a disqualifier.A
is disqualified due to its constructors; containing astring
isn't a reason.B
is an aggregate, sinceA
not being one isn't a disqualifier. – Mcneal