In what cases can't a modern day compiler apply the NRVO optimization for functions?

282 views Asked by At

In general I would like to know when and why a modern day compiler, say gcc 4.7 and up using c++11, can not apply an NVRO optimization.

EDIT: I oversimplified this code mistakenly not returning any local variables. A better example was supplied by @cooky451 below see ideone.com/APySue

I saw some snippets of code to answers on other questions that were as such

A f(A&& v)
{
  return v;
}

and they were changed to be

A f(A&& v)
{
  return std::move(v);
}

because they said that the rvalue passed in which is assigned to an lvalue v was still an rvalue and could be moved. However, others wrote that this will remove the ability for NVRO. Wny is this? If the compiler knows that a temporary is being returned can't it construct it directly in place without moving anything? I guess I don't understand why case one would have NVRO but not case 2. I might have the facts wrong hence the question. Also, I read that case 2 was an anti pattern for this reason and that you shouldn't return std::move like this. Any additional insight would be helpful. I was told that behind the scenes the compiler will create something like this below: A& __hidden__ is the assignment to the function, myValue in this case.

A myValue = f(A());

// behind the scenes pseudo code for direct in place construction

void f(A&& v,  A& __hidden__ )
{
    __hidden__ = v;
    return;
}
1

There are 1 answers

8
cooky451 On BEST ANSWER

Both won't use RVO, because it's impossible. The problem is: && is still just a reference. The variable you're returning is not inside your function-local scope! So, without std::move, you'll copy, and with it you'll move. I would advice btw not to expect something per rvalue-reference, as long as you're not writing a move constructor/assignment operator or some perfect-forwarding template-code. Just take it by value. It has a small overhead in some cases, but it's really not going to be significant. And it makes code a lot more readable. And simpler, as the caller can either copy or move the arguments, and you don't have to provide additional const& overloads.