Search code examples
c++c++11autoconst-reference

const auto& for storing functions results, is it worthwhile?


Let assume that we have a function that returns a complex object like std::string:

std::string find_path(const std::string& filename);

Is it worthwhile to store the result of calling that method in the const auto&?

void do_sth() {
   //...
   const auto& path = find_path(filename);
   //...
} 

That kind of approach prevents copying/moving the object. So it is good. But on the other hand, auto has been introduced to unify the left side of assignation. Herb Sutter in his presentation from CppCon2014 mentions about C++ left-to-right modern style https://www.youtube.com/watch?v=xnqTKD8uD64 (39:00-45:00).

In C++98 storing the std::string at const ref was fine. How is it in C++11?

Update (2016-07-27 2:10 GMT+0):

Sorry, my question was not precise. I meant the coding style - is it better to add const & or just stay with auto only and let the compiler do whatever it want.

Updated example:

unsigned int getTimout() { /* ... */ }

int getDepth() { /* ... */ }

std::string find_path(const std::string& filename,
                      unsigned int timeout,
                      int depth) { /* ... */ } 

void open(const std::string& path) { /* ... */ }

Two approaches:

void do_sth() {
   //...
   auto timeout = getTimeout();
   auto depth = getDepth();
   const auto& path = find_path(filename, timeout, depth);
   open(path)
   //...
} 

vs

void do_sth() {
   //...
   auto timeout = getTimeout();
   auto depth = getDepth();
   auto path = find_path(filename, timeout, depth);
   open(path);
   //...
}

The question: should we

  • use const auto& to store complex return objects and auto for primitives, or
  • use auto for everything to keep the left-to-right modern C++ style that Herb mentioned in his presentation (link above).

Solution

  • In C++98 storing the std::string at const ref was fine. How is it in C++11?

    Binding a const reference to a temporary string object is fine in C++11. It still has the same behaviour as before.

    The theoretical cost of copy-initialization from a temporary (avoiding of which is the advantage of using a const reference) has been greatly reduced in C++11, since moving a string is far cheaper than copying.

    The practical cost of copy-initialization has not changed with optimizing compilers, because they may elide the copy/move anyway, so there is no cost - although, whether that is possible, depends on how find_path is implemented.


    If you absolutely want to avoid copying/moving the returned string and cannot assume copy elision, then you must create the object outside the function, and pass it to the function by reference. Binding a reference to the return value is not sufficient.

    If you want to avoid copying/moving the returned string and can assume copy elision, then using a regular object is just as good as a const reference.