2

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?
Fedor
  • 17,146
  • 13
  • 40
  • 131

0 Answers0