Skip to content

Instantly share code, notes, and snippets.

@unixod
Last active October 29, 2019 09:22
Show Gist options
  • Save unixod/ba85507bbf90d3809874d741305e3a1f to your computer and use it in GitHub Desktop.
Save unixod/ba85507bbf90d3809874d741305e3a1f to your computer and use it in GitHub Desktop.
Interesting case.
// This example is supposed to be compiled using C++17 standard.
#include <utility>
static_assert(__cpp_guaranteed_copy_elision);
struct X {
char k[17];
};
struct A {
#ifdef ENABLE_CONSTRUCTOR
A(X&& obj)
: obj{std::move(obj)}
{}
#endif
X obj;
};
X getx();
void usea(A&);
int buz()
{
A a{getx()};
usea(a);
return 0;
}
@unixod
Copy link
Author

unixod commented Oct 29, 2019

My understanding of why defining ENABLE_CONSTRUCTOR makes gcc 9.2 and clang 9.0.0 introduce additional copying of X in compiled code.

When ENABLE_CONSTRUCTOR isn't defined, A is an aggregate class type and at line 27 we have an aggregate initialization, hence X is copy-initialized from the result of getx which is prvalue of the same type (X) => a mandatory copy elision is performed.
When ENABLE_CONSTRUCTOR is defined, A isn't an aggregate class type => we have direct list initialization of A with prvalue X => compilers aren't obligated to eliminate copy operation for X.

Another question: according to https://en.cppreference.com/w/cpp/language/direct_initialization, for class types we should consider the direct-list-initialization: https://en.cppreference.com/w/cpp/language/list_initialization which doesn't say anything about colpy/move elision, why?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment