Copy/move elision requires explicit definition of copy/move constructors

  • A+
Category:Languages

Consider the following program:

#include <iostream> #include <utility>  class T { public:     T() { printf("address at construction:    %zx/n", (uintptr_t)this); }     // T(const T&) { printf("copy-constructed/n"); } // helps     // T(T&&) { printf("move-constructed/n"); }      // helps     // T(const T&) = default;                        // does not help     // T(T&&) = default;                             // does not help };  T f() { return T(); }  int main() {     T x = f();     printf("address after construction: %zx/n", (uintptr_t)&x);     return 0; } 

Compiling with g++ -std=c++17 test.cpp gives the following output (same with clang++):

address at construction:    7ffcc7626857 address after construction: 7ffcc7626887 

Based on the C++ reference I would expect the program to output two equal addresses because the copy/move should be guaranteed to be elided (at least in C++17).

If I explicitly define either the copy or the move constructor or both (see commented out lines in the example), the program gives the expected output (even with C++11):

address at construction:    7ffff4be4547 address after construction: 7ffff4be4547 

Simply setting the copy/move constructors to default does not help.

The reference explicitly states

[The copy/move constructors] need not be present or accessible

So what am I missing here?


Because this is a special case where copy elision may not apply.

Quoted from [class.temporary] paragraph 3:

When an object of class type X is passed to or returned from a function, if each copy constructor, move constructor, and destructor of X is either trivial or deleted, and X has at least one non-deleted copy or move constructor, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the non-deleted trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). [ Note: This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. — end note ]

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: