Search code examples
c++returninstantiationcreation

When returning an object, why put the creation+initialization and the return as two seperate statements instead of one?


Example:

Foo make_foo(int a1, int a2){
  Foo f(a1,a2);
  return f;
}

Having seen such functions several times, is it just a matter of coding style / preference or is there more to it than meets the eye? Specifically this answer got me thinking with the make_unique implementation and the claim it is exception safe - is that related to the splitting of creation and return? Or am I reading too much into this? Why not simply write

Foo make_foo(int a1, int a2){
  return Foo(a1,a2);
}

Solution

  • Note that the answer to which you refer actually has something different:

    std::unique_ptr<T> ret (new T(std::forward<Args>(args)...));
    

    In this line of code, explicit dynamic allocation is performed. Best practices dictate that whenever you perform explicit dynamic allocation, you should immediately assign the result to a named smart pointer. For more details, consult the Boost shared_ptr best practices documentation or Herb Sutter's GotW article, "Exception-Safe Function Calls."

    It isn't always dangerous to have a new expression as a subexpression of a larger expression, but it's a rule that is easy to forget, so it's best to always follow the best practices guideline and assign a new dynamically allocated object to a named smart pointer.


    That said, there is at least one advantage to the pattern of creating a named object and then returning it: it can be a bit easier to "watch" the object in the debugger when stepping through code quickly.

    One possible disadvantage is that it is potentially more difficult for a compiler to perform Return Value Optimization (RVO) with a named object. Named Return Value Optimization (NRVO) is not always as straightforward as RVO with an unnamed temporary. I'd hazard to guess that modern compilers wouldn't have a problem either way, but I am not an expert on C++ compiler optimizations.