Here is a C++ 14 program for comparing direct initialisation (no =
) with copy initialisation (=
):*
#include <iostream>
struct A {
A(int) { std::cout << "A(int)" << std::endl; }
A(A&) { std::cout << "A(A&)" << std::endl; }
A(A&&) { std::cout << "A(A&&)" << std::endl; }
};
int main() {
A a(1); // direct initialisation
A b{1}; // direct initialisation
A c = 1; // copy initialisation
A d = (1); // copy initialisation
A e = {1}; // copy initialisation
}
Compiling the program with copy elision disabled and running it:
$ clang++ -std=c++14 -fno-elide-constructors main.cpp && ./a.out
produces the following output:
A(int)
A(int)
A(int)
A(A&&)
A(int)
A(A&&)
A(int)
Why does copy initialisation with braces (A e = {1};
) elide copy/move construction (even with copy elision disabled)?
* The motivation behind this comparison was to understand how a function return statement (return expression
) works since C++ 11. When returning by value, one can use direct initialisation or copy initialisation of the function return value. The latter is more complex than copy initialisation of a variable like here, because initialising the function return value from the object denoted by expression
involves trying to call the move constructor of the function return type first (even if expression
is an lvalue) before falling back on its copy constructor. And since C++ 17, that copy/move construction is guaranteed to be elided if expression
is a prvalue (mandatory return value optimisation), while it might be elided if expression
is a glvalue (optional named return value optimisation).