5

If I get it correctly, move semantics allows to move and reuse resources from temporary, unnamed objects. RVO, albeit preceding move semantics goes further and "steals" the entire object to avoid the extra constructor call and assignment/copy function.

This seems a bit counter intuitive to me, wouldn't it be that much faster, simple and user obvious if the called constructor uses directly the address of the final lvalue target to directly emplace data where the user needs it?

I mean, "create this object in this location" seems a bit more intuitive than "create this object somewhere, then copy it to its right location".

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Nice question. I don't have time to think of a full answer, but I believe call chaining would make this a nightmare (e.g. `A a = f(g(), h(i(), j()), k(l()));`). Now the user would have to tell each of `f`, `g`, `h`, `i`, `j`, `k` and `l` where it should create its return values. – Angew is no longer proud of SO Dec 17 '13 at 11:40
  • @Angew - in this case, only `f()` will return directly to the address of `a`, the rest will return to the addresses of their temporary objects used to call `f()`. After all, the only assignment is from the return of `f()` to `a`. –  Dec 17 '13 at 11:46
  • Yes, but the way I understand it, these temporaries can be constructed directly in the parameters' locations (RVO) or in the functions' return value locations. – Angew is no longer proud of SO Dec 17 '13 at 12:17
  • This (closely) answers, i think, the same question "What optimization does move semantics provide if we already have RVO?" - http://stackoverflow.com/questions/5031778/what-optimization-does-move-semantics-provide-if-we-already-have-rvo – SChepurin Dec 17 '13 at 12:18
  • @Angew - yes, the optimal way would be to emplace the return values from the functions right on the spot they need to be, in the case of the inner calls that would be directly in the parameter slot, for `f()` it would be the location of `a`. After all, the point is to eliminate copy/assignment. But it is not necessary for the user to explicitly provide return addresses, the compiler can deal with that, for both lvalue and rvalue as lvalue slots. After all, the user cannot specify the address of a unnamed temporary even if he wanted to. –  Dec 17 '13 at 12:29
  • 2
    @user2341104 If you're happy with the compiler providing the addresses, then I must have misunderstood the question. RVO is precisely "create this object at this location." So what are you actually asking about? – Angew is no longer proud of SO Dec 17 '13 at 12:32
  • @Angew - it is not a "black or white" scenario - for temporary objects, it is OK for the compiler to do it, especially considering that the user cannot, but there is no explicit way to emplace the object and avoid the rvo optimization, like for example some container classes emplace. This way, the source code expresses the developer intent more directly, without optional optimizations being needed to produce optimal code. –  Dec 17 '13 at 13:20
  • To add to possible problems: What if there is no object to construct in? A function returning an object can be called without any assignment, i.e. `f();` instead of `X x = f();`. – dornhege Dec 17 '13 at 14:55
  • Good question. I think there are so many rules of thumb floating around that it's a nightmare to internalize it all when you're moving to C++11. – Kristian D'Amato Dec 17 '13 at 15:14
  • @dornhege - it's simple, no object to construct in = unnamed temporary. –  Dec 17 '13 at 15:32

1 Answers1

7

Yes it is "a bit counter intuitive". With copy elision enabled all side effects of the constructor are elided, too.

#include <iostream>

struct X {
    X() { std::cout << "Construct" << std::endl; }
    X(X&&) { std::cout << "Move" << std::endl; }
    ~X() { std::cout << "Destruct" << std::endl; };
};

X f() { return X(); }

int main()
{
    X x(f());
    return 0;
}

Copy elision: g++ -std=c++11 src-test/main.cc

Construct
Destruct

No copy elision: g++ -std=c++11 -fno-elide-constructors src-test/main.cc

Construct
Move
Destruct
Move
Destruct
Destruct

The compiler, knowing the hardware the program/library is build for, is able to apply (optional) copy elision. The C++ language, itself, is not aware of hardware specific return mechanisms. Hence it is not possible to construct at a certain address in this context.