In the following code, struct B
is an aggregate with base struct A
, and B
-object is aggregate initialized B b{ A{} }
:
#include <iostream>
struct A {
A() { std::cout << "A "; }
A(const A&) { std::cout << "Acopy "; }
A(A&&) { std::cout << "Amove "; }
~A() { std::cout << "~A "; }
};
struct B : A { };
int main() {
B b{ A{} };
}
GCC and MSVC perform A
copy elision, printing:
A ~A
while Clang creates a temporary and moves it, printing:
A Amove ~A ~A
Demo: https://gcc.godbolt.org/z/nTK76c69v
At the same time, if one defines struct A
with deleted move/copy constructor:
struct A {
A() {}
A(const A&) = delete;
A(A&&) = delete;
~A() {}
};
then both Clang (expected) and GCC (not so expected in case of copy elision) refuse to accept it, but MSVC is still fine with it. Demo: https://gcc.godbolt.org/z/GMT6Es1fj
Is copy elision allowed (or even mandatory) here? Which compiler is right?
There is a related question Why isn't RVO applied to base class subobject initialization? posted 4 years ago, but
- this question askes about peculiarities of aggregate initialization, not covered there;
- as one can see copy elision is applied in the above example by 2 out of 3 tested modern compilers. Is it due to bugs in these compilers (still present after 4 years) or they are allowed doing so?