4

It's my first year of using C++ and learning on the way. I'm currently reading up on Return Value Optimizations (I use C++11 btw). E.g. here https://en.wikipedia.org/wiki/Return_value_optimization, and immediately these beginner examples with primitive types spring to mind:

int& func1()
{
    int i = 1;
    return i;
} 
//error, 'i' was declared with automatic storage (in practice on the stack(?)) 
//and is undefined by the time function returns 

...and this one:

int func1()
{
    int i = 1;
    return i;
}
//perfectly fine, 'i' is copied... (to previous stack frame... right?)

Now, I get to this and try to understand it in the light of the other two:

Simpleclass func1()
{
    return Simpleclass();
}

What actually happens here? I know most compilers will optimise this, what I am asking is not 'if' but:

  • how the optimisation works (the accepted response)
  • does it interfere with storage duration: stack/heap (Old: Is it basically random whether I've copied from stack or created on heap and moved (passed the reference)? Does it depend on created object size?)
  • is it not better to use, say, explicit std::move?
Enlico
  • 23,259
  • 6
  • 48
  • 102
DailyFrankPeter
  • 382
  • 1
  • 13
  • Possible duplicate of [Does return statement copy values](http://stackoverflow.com/questions/1529447/does-return-statement-copy-values) – Aracthor Jan 14 '17 at 12:24
  • _Is it basically random whether I've copied from stack or created on heap_ No, it is created on stack. – Algirdas Preidžius Jan 14 '17 at 12:24
  • Why would the heap be involved? Implementation is explained pretty well in the article you linked. – molbdnilo Jan 14 '17 at 12:28
  • I get the gist of n. r. v. optimisation now. As for why I wrote 'heap', I was under the impression that larger objects don't fit on the stack, and this is also why it is called 'automatic storage' declaration. But maybe that's another thing I misunderstand. – DailyFrankPeter Jan 14 '17 at 14:58

1 Answers1

8

You won't see any effect of RVO when returning ints.

However, when returning large objects like this:

struct Huge { ... };

Huge makeHuge() {
    Huge h { x, y, x };
    h.doSomething();
    return h;
}

The following code...

auto h = makeHuge();

... after RVO would be implemented something like this (pseudo code) ...

h_storage = allocate_from_stack(sizeof(Huge));
makeHuge(addressof(h_storage));
auto& h = *properly_aligned(h_storage);

... and makeHuge would compile to something like this...

void makeHuge(Huge* h_storage) // in fact this address can be
                               // inferred from the stack pointer
                               // (or just 'known' when inlining).
{
    phuge = operator (h_storage) new Huge(x, y, z);
    phuge->doSomething(); 
}
Enlico
  • 23,259
  • 6
  • 48
  • 102
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142