3
//old school '98 c++, no C++0x stuff
std::string getPath();

void doSomething()
{
    const std::string &path = getPath(); //const reference to an rvalue
    ... // doSomething with path
}

void doSomething2()
{
    const std::string path = getPath(); //regular variable
    ... // doSomething with path
}

what are the differences between doSomething and doSomething2 and which one is prefferable?
Is it safe to use const reference to returned rvalue in doSomething?
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?

Pavel P
  • 15,789
  • 11
  • 79
  • 128

3 Answers3

4

Is it safe to use const reference to returned rvalue in doSomething?

Yes, this is perfectly fine. The language has an specific clause that guarantees that if you bind a reference to an rvalue a temporary is created and the lifetime is extended until the end of the scope where the reference is created.

Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?

In both cases the cost is the same, as the compiler will do RVO (return value optimization)

what are the differences between doSomething and doSomething2 and which one is prefferable?

The main difference is that in one case you are giving a name to the real object and in the other case the name is given to a reference. The compiler should generate exactly the same code in both versions.

That being said, I find the use of the const& to be misleading. It gives the impression that the local function has a reference to some object somewhere, but it really has a copy (with no name). To realize that this is a copy the maintainer will have to look and verify the signature of the function that is being called. In the case of the value the behavior is more obvious: the function maintains a copy of whatever is returned by the function (which might be a value or reference).

The second difference is that you are only legally allowed to bind a const reference, which means that the function cannot modify the object. In the case of storing a value, the type can be non-const and the function could modify that object, so the approach is more flexible.

In C++03 the only reason to use the const& trick is in the case where you know that the function returns a value, you know that the type derives from a well known base, and you don't want to name the type [Take a look at ScopeGuard]. In C++11 that use is no longer important, as you can just use auto to let the compiler figure out the type automatically.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
0

(from other comments it seems this might be C++ standards version dependant as to guarentees when you bind a reference to an rvalue about its lifespan - this answer reflects C++ classic)

doSomething has a reference to what?

doSomething2 has a copy of something that may not exists anymore which is fine

lets look at getPath():

in general it will take the return value, copy it to the stack and then copy that to the lhs it can just assign directly to the lhs

it can return "hello" which will create a string on the stack - this cannot be referenced because it is temporary (the problem with doSomething)

it can return a static const string - in which case it can be completely inlined and assigned to the lhs

Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
  • This is wrong, the language guarantees that the temporary lifetime will be extended until the end of the scope in which the reference lives. – David Rodríguez - dribeas Nov 21 '13 at 05:17
  • @DavidRodríguez-dribeas - i noted your answer and was editing my response to mention - standards versions may vary on lifetime guarentees - this answer may be useful for those that still have older compilers and have core dumps - note the OP comment `//old school c++, no C++0x stuff` – Glenn Teitelbaum Nov 21 '13 at 05:23
-1

The reference version could have a dangling reference if the std::string was allocated inside the function getPath() and destroyed when returning from that function. Then, it's dangerous usage.

If you had a class holding that string and the class outlives the scope of that const std::string & reference, something as MyClass::getPath(), then, in that case, the reference wouldn't be dangling.

The second version will always work.

Germán Diago
  • 7,473
  • 1
  • 36
  • 59
  • 1
    This is wrong, the language guarantees that the reference can be bound and that the lifetime of the temporary will be extended for the duration of the scope in which the reference lives. – David Rodríguez - dribeas Nov 21 '13 at 05:16
  • Even if it's allocated in the stack and the function returns? It seems weird to me, you are using a const lavalue reference in this case. – Germán Diago Nov 21 '13 at 07:32
  • Note that the reference is bound to a function that returns by value. The lifetime of the temporary is extended to the end of the current scope (where the reference lives). If the function exits (either returns or throws) the scope of the reference is closed and the temporary is destroyed. – David Rodríguez - dribeas Nov 21 '13 at 14:09
  • it's clear what `getPath` does by its declaration, it's irrelevant how it does this – Pavel P Nov 21 '13 at 20:20