Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will member subobjects of local variables be moved too if returned from a function?

The C++11 standard states that, if the conditions for copy elision are met (§12.8/31), the implementation shall treat a returned local lvalue variable and function parameters, as an rvalue first (move), and if overload resolution doesn't succeed as detailed, shall then treat it as an lvalue (copy).

§12.8 [class.copy] p32

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]

Does this also include member subobjects? I tested with the following snippet:

#include <iostream>

struct traced{
  traced(){ std::cout << "default ctor\n"; }
  traced(traced const&){ std::cout << "copy ctor\n"; }
  traced(traced&&){ std::cout << "move ctor\n"; }
};

struct X{
  traced t;
};

traced f(){
  X x;
  return x.t;
}

int main(){
  traced t = f();
}

Live example on Ideone. And neither GCC 4.7 ToT nor Clang 3.1 ToT will display "move ctor", which leads me to believe that the standard doesn't include member subobjects.

Did I overlook something? Is my test code broken? What exactly causes the output to be as it is?

like image 328
Xeo Avatar asked Feb 07 '12 20:02

Xeo


1 Answers

When returning a subobject you can't elide its construction. Think of it this way: move and copy elision essentially amount to constructing the object in the place it would eventually be moved or copied to. This works for complete objects because there will be the appropriate space be set aside. It doesn't work with subobjects because you would construct the enclosing object. Even if this has the same size as the subobject, i.e. there is enough space, the enclosing object gets destroyed and may do funny things to the subobjects.

Effectively, this means that construction of the subject cannot be elided.

like image 134
Dietmar Kühl Avatar answered Oct 15 '22 17:10

Dietmar Kühl