Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return value optimization vs auto_ptr for large vectors

Tags:

c++

auto-ptr

rvo

If I use auto_ptr as a return value of a function that populates large vectors, this makes the function a source function (it will create an internal auto_ptr and pass over ownership when it returns a non const auto_ptr). However, I cannot use this function with STL algorithms because, in order to access the data, I need to derefference the auto_ptr. A good example I guess would be a field of vectors of size N, with each vector having 100 components. Wether the function returns each 100 component vector by value or by ref is not the same, if N is large.

Also, when I try this very basic code:

class t
{
    public: 
         t() { std::cout << "ctor" << std::endl; }
         ~t() { std::cout << "dtor" << std::endl; }
};

t valueFun()
{
   return t();
}

std::auto_ptr<t> autoFun()
{
   return std::auto_ptr(new t());
}

both autoFun and fun calls result with the output

Ctor Dtor

so I cannot actually see the automatic variable which is being created to be passed away to the return statement. Does this mean that the Return Value Optimization is set for the valueFun call? Does valueFun create two automatic objects at all in this case?

How do I then optimize a population of such a large data structure with a function?

like image 628
tmaric Avatar asked May 04 '12 13:05

tmaric


1 Answers

There are many options for this, and dynamic allocation may not be the best.


Before we even delve in this discussion: is this a bottleneck ?

If you did not profile and ensured it was a bottleneck, then this discussion could be completely off... Remember than profiling debug builds is pretty much useless.


Now, in C++03 there are several options, from the most palatable to the least one:

  • trust the compiler: unnamed variables use RVO even in Debug builds in gcc, for example.
  • use an "out" parameter (pass by reference)
  • allocate on the heap and return a pointer (smart or not)
  • check the compiler output

Personally, I would trust my compiler on this unless a profiler proves I am wrong.

In C++11, move semantics help us getting more confident, because whenever there is a return statement, if RVO cannot kick in, then a move constructor (if available) can be used automatically; and move constructors on vector are dirt cheap.

So it becomes:

  • trust the compiler: either RVO or move semantics
  • allocate on the heap and return a unique_ptr

but really the second point should be used only for those few classes where move semantics do not help much: the cost of move semantics is usually proportional to the return of sizeof, for example a std::array<T,10> has a size equal to 10*sizeof(T) so it's not so good and might benefit from heap allocation + unique_ptr.


Tangent: you trust your compiler already. You trust it to warn you about errors, you trust it to warn you about dangerous/probably incorrect constructs, you trust it to correctly translate your code into machine assembly, you trust it to apply meaningful optimization to get a decent speed-up... Not trusting a compiler to apply RVO in obvious cases is like not trusting your heart surgeon with a $10 bill: it's the least of your worries. ;)

like image 129
Matthieu M. Avatar answered Oct 12 '22 04:10

Matthieu M.