Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why NRVO is not applied here?

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?

like image 757
Belloc Avatar asked Apr 16 '13 13:04

Belloc


2 Answers

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.

like image 132
Andy Prowl Avatar answered Oct 18 '22 06:10

Andy Prowl


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
like image 1
Kerrek SB Avatar answered Oct 18 '22 07:10

Kerrek SB