When is an rvalue evaluated?
Asked Answered
S

2

6

So I understand that s2 binds to the expression s1 + s1, but is this evaluated at the time s2 is assigned or is it lazy and evaluated when s2 += "Test"; is called? And also would s2 hold memory for a temporary string?

#include <iostream>
#include <string>

int main()
{
    std::string s1 = "Test";
    std::string&& s2 = s1 + s1;
    s2 += "Test";
    std::cout << s2 << '\n';
}
Stromboli answered 1/6, 2017 at 4:15 Comment(0)
C
16

s2 binds to the expression s1 + s1, but is this evaluated at the time s2 is assigned

Yes.

And also would s2 hold memory for a temporary string?

Precisely, s2 is bound to a temporary std::string.

s1 + s1 will produce a temporary std::string, which will be bound to the reference s2 (and its lifetime is extended to the lifetime of the reference). Then s2 += "Test";, performs operator+=() on s2, i.e. the temporary std::string.

Contradance answered 1/6, 2017 at 4:19 Comment(5)
Thanks for the quick reply. It seems that if s2 was just another std::string, the results will be the same, but would the resulting binaries be any different?Stromboli
@BradyDean Yes the result is the same. It's hard to say about the result binaries; Anyway I tried it here and it gave the same assembly.Contradance
Note that this changes in C++17 in a way that makes zero observable difference in this case.Rosaniline
@Yakk You mean temporary materialization?Contradance
@Contradance Yes. s1+s2 is a prvalue, which is then materialized into a temporary. Very, very slight difference.Rosaniline
P
2

Expressions are always evaluated at the point the program reaches them. The result of an expression is always a value (or void).

Values have a type, and expressions have a value category, which combine to choose which overload of an overload set is used, at any particular use.

In your case, string operator+(...) results in a string value, with the category pr-value (which is a type of rvalue). It is then immediately bound to a string&&, so it's lifetime is extended to that of the reference.

If you had instead assigned it to a plain string, string& string::operator=(string&&) would have been chosen over any other overloads of that operator. Note that since c++11 the compiler is allowed (and from c++17 required) to materialize the value directly inside the target object. This process is known as copy/move elision or (N)RVO, for (Named) Return Value Optimisation.

Pressurize answered 1/6, 2017 at 12:5 Comment(2)
@Yakk Which things particularly? To my knowledge the only change is that the move construction is elided, and that isn't observably different to c++14 for stringPressurize
Sorry, I swore I saw the word "object" where it wasn't supposed to be, but I don't see it now, so I must have been wrong.Rosaniline

© 2022 - 2024 — McMap. All rights reserved.