8

NRVO is not applied when I run this code in VS2010.

#include <stdio.h>

class A
{
    public:

    A() { printf( "I am in constructor\n" ); }
    A(const A& a) { printf( "I am in copy constructor\n" ); }
    ~A() { printf( "I am in destructor\n" ); }
    int i;       
};

A f(int j)
{
    A a;
    if ( j )  return a;
    a.i = j;
    return a; 
}

int main()
{
    A a;
    a = f(5);
}

Edit: this has something to do with the destructor. When I comment out its line, NRVO is used. But why is this?

Belloc
  • 6,318
  • 3
  • 22
  • 52
  • 5
    What level of optimization are you using? Also note that it is much simpler to apply NRVO if there is a single return, which in this case is trivial, substituting the `if`: `if (!j) a.i = j;` then it will have higher chances of being applied. – David Rodríguez - dribeas Apr 16 '13 at 13:38
  • 1
    look here, http://msdn.microsoft.com/en-us/library/ms364057%28v=vs.80%29.aspx there are limitations of NRVO. Are you sure, you have optimizations enabled? – kassak Apr 16 '13 at 13:39
  • @DavidRodríguez-dribeas I've tried with all optimization options and the result is the same. – Belloc Apr 16 '13 at 13:44
  • 1
    @user1042389: Your example is very similar to "Sample 5" in kassak's link, where optimisation fails because the destructor makes control flow too complicated for the compiler to analyse. Also in that link, it says "This is actually something that Visual C++ 2005 will need to improve in the future" - perhaps they didn't get round to making that improvement before 2010. – Mike Seymour Apr 16 '13 at 14:01
  • @MikeSeymour But it is the destructor that is preventing the optimization. Any idea why is this so? – Belloc Apr 16 '13 at 14:10
  • @user1042389: I've no idea, beyond what that article says. It causes some kind of problem for the compiler's optimisation logic, so the compiler gives up trying to optimise it. Other compilers don't have that limitation. – Mike Seymour Apr 16 '13 at 14:12

2 Answers2

6

Why NRVO is not applied here?

If this purely a curiosity of yours, and you want to know how VC10 algorithmically decides whether or not to perform NRVO, then the only people who could answer this question reliably are those who know how VC10 works internally - those who wrote it.

For what I can tell, according to the C++11 Standard the compiler is allowed to perform NRVO in this situation, and not doing so is just a compiler's decision - not due to any validity constraint. Per Paragraph 12.8/31:

[...] This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

[...]

However, if you are asking with the expectation that you should be able to force your compiler to perform NRVO, then the answer is "You cannot".

It is completely at a compiler's discretion whether or not to apply NRVO. You cannot count on it, and you cannot count on it not being performed. This is, to the best of my knowledge, the only exception to the so-called "as-if" rule.

This said, chances to get NRVO being performed increase as you increase the level of optimization.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • I'm just curious to know why it's not applied here. – Belloc Apr 16 '13 at 13:47
  • @user1042389: OK. In this case it will be hard to get an answer. What I can tell is that the C++ Standard does allow NRVO, so the answer is not "because it isn't allowed". – Andy Prowl Apr 16 '13 at 13:53
1

I don't know what you see in your environment, but this works as expected in GCC (e.g. see here):

Normal:

I am in constructor
I am in constructor
I am in destructor
I am in destructor

With -fno-elide-constructors:

I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I'm getting your second output in a release build, i.e., with optimizations enabled, in VS2010. – Belloc Apr 16 '13 at 13:39