3

Let there be a class A with a move constructor. Consider this:

A get()
{
    A a;
    return std::move( a );
}

// later in the code
A aa = get();

Here the explicit call to std:move forces the move constructor of A to be called thus it might inhibit the return value optimization in while calling get(). Thus it is said the a better implementation of get() would be this:

A get()
{
    A a;
    return a;
}

But the return value optimization is not a part of C++11 standard, so WHAT IF the compiler, by some reason, decides not to perform return value optimization while calling get(). In this case a copy constructor of A will be called while returning in get() right?

So isn't the first implementation of get() more pereferible??

Xeo
  • 129,499
  • 52
  • 291
  • 397
Vahagn
  • 4,670
  • 9
  • 43
  • 72
  • 3
    What if your compiler decides to insert a million nops before every function call? You have to choose your tools... And RVO *is* explicitly part of the standard, it's just not *mandatory*. – Kerrek SB Aug 14 '13 at 09:34
  • 4
    There is no need for `std::move`. If accessable, the move constructor of A will be called by 12.8/32. – MWid Aug 14 '13 at 10:21
  • @MWid At 12.8/32 in the example the copy constructor is private/ Would the code behave the same if it were public? – Vahagn Aug 14 '13 at 12:03
  • 3
    @Vahagn Yes. It is a two-stage overload resolution. First, the object returned is treated as rvalue. If overload resolutions fails in that case, then it is treated as lvalue. The point here is, that the type of the object returned is the same as the return type of your function... – MWid Aug 14 '13 at 12:15
  • 3
    If you return an object of type `A`, but the return type of the function would be `B` and `B` has a (move) constructor taking an `A` as argument, then you explicitely must write `move` if you want move semantics. – MWid Aug 14 '13 at 12:17
  • 2
    Just one additional note: If the move constructor would be private or deleted, then the code would not compile, regardless of wether the copy constructor is public or private. – MWid Aug 14 '13 at 12:41
  • @MWid at 12.8/32 it says "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,...". The "source object" is "the object to be copied", isn't it? And in the example that object is local to the function, not a function parameter, right? – Vahagn Aug 14 '13 at 13:13
  • The source object is the object to be copied/returned. And this can be a function parameter: `A f(A a) { return a; }` – MWid Aug 14 '13 at 13:25
  • @MWid -- I just got the opposite meaning for idiom "save for the fact" ։) Now everything is clear. Thanks a lot. – Vahagn Aug 14 '13 at 14:26

1 Answers1

3

A compiler should use a move constructor, but I didn't see an obligation in the standard : It's always said "Copy/move constructor" in the section concerning temporary objects

standard ISO/IEC 14882:2011 C++ :

"

12.1/9

A copy constructor (12.8) is used to copy objects of class type. A move constructor (12.8) is used to move the contents of objects of class type.

12.8/32

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 ]

"

lvalue = T &
rvalue = T &&

So, It says that first, the compiler will look if it find a move constructor, then, it will look for a move constructor.

Thus, if your compiler is conform to the standard, it will call the move constructor.

I append just that which is interesting:

"
12.8/31 When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects.
"

...So even if there is side effects in these constructors/destructors, they can be skipped

hl037_
  • 3,520
  • 1
  • 27
  • 58