(Named) Return Value Optimization in Visual Studio 2010

I’ve made a few tests with VS2010 for Named Return Value optimization (NRVO). NRVO is a mechanism compilers use to pass the return capture of a statement and passes it as an argument to a function for you. For example, if you do

std::string MyStringFunc()
{
  return std::string( "The answer to life, the universe and everything is 42" );
}
std::string str = MyStringFunc();

Then the compiler guarantees that only one string will be created, the returned value, and that “str” will store that value. So what this means, is that you’ll save a copy. But one thing must be said about this, VS2010 only enable this optimisation with /O2 meaning that you won’t get the same behavior in Debug and Release builds, so caution must be taken.
In the following snippet, you’ll see that we don’t get the same result in Debug and Release:

#include <tchar.h>
#include <iostream>
#include <vector>
struct MyStruct
{
  // Default constructor
  MyStruct()
  {
    std::cout << "First" << std::endl;
    floats.resize( 1000000 );
    floats[0] = 76;
  }
  // Copy constructor
  MyStruct(const MyStruct& r) 
    : i(r.i)
    , j(r.j)
    , floats(r.floats)
  { 
    std::cout << "Copy" << std::endl; 
  }
  // Move constructor
  MyStruct(const MyStruct&& r) 
    : i(r.i)
    , j(r.j)
    , floats(std::move(r.floats))
  { 
    std::cout << "Move" << std::endl; 
  }
  // Destructor
  ~MyStruct()
  {
    std::cout << "Destruct" << std::endl; 
  }
  int i;
  int j;
  std::vector<float> floats;
};
 
const MyStruct GetVar()
{
  MyStruct s; // First
  s.i = 42;
  s.j = 24;
  return s; // Copy or Move or Nothing with /O2
}
 
int _tmain(int argc, _TCHAR* argv[])
{
  const MyStruct r = GetVar();
  std::cout << "Result: " << r.i << " " << r.j << " " << r.floats[0] << std::endl;
  return 0;
}

If you run this in debug, you’ll get :

First
Move
42 24 76

And in Release you’ll get :

First
42 24 76

Saving the copy that can be costly. You get the same behavior with or without the explicit copy or move constructor. The move constructor is used by default if defined.

So the lesson is: don’t stop yourself from returning structures, but be aware that the code won’t flow the same in debug and release.

This entry was posted in C++, Coding, Snippet and tagged . Bookmark the permalink.

2 Responses to (Named) Return Value Optimization in Visual Studio 2010

  1. Fernando says:

    Just a word of caution: NRVO and RVO are two different things. In your first snippet of code you are invoking plain RVO. The returned object is an unnamed temporary, so it is easy to optimize away. In your second example you are returning an object that you created on the stack and that you used in your function, thus a named object, and hence the ‘N’ in NRVO. This is a little bit trickier for the compiler to handle, and care should be taken because there are some restrictions as to when this optimization can be effective: multiple return paths, exceptions, etc.

  2. Jonathan says:

    You are right. Thanks for the clarification.

Leave a Reply

Your email address will not be published. Required fields are marked *