๐ฅ Explore this must-read post from Hacker News ๐
๐ Category:
๐ Main takeaway:
This is part one of a series of blog posts on temporaries, copies, return value optimization, and passing by value vs. reference.
A good place to start, and the point of this first article, is how a prvalue isnโt necessarily a temporary.
If youโre entirely new to value categories (lvalues, rvalues etc.), you might want to read lvalues, rvalues, glvalues, prvalues, xvalues, help! first.
lvalues vs rvalues
An lvalue is an expression that can not be moved from. An rvalue is an expression that can be moved from.
Letโs first have a look at lvalues. Given this variable v:
If I now write the expression v somewhere, v is referring to an actual variable. I canโt just move from it, as it would mess up an existing object that someone else could still be using. We call an expression like this an lvalue.
For instance, if I pass my existing vector to a function useVector:
Here, the expression v is an lvalue, and useVector canโt move from it. After all, someone might want to keep using v on a following line.
But if I know I wonโt be needing v anymore, I can turn it into an rvalue, by wrapping it in std::move:
Here, the expression std::move(v) is an rvalue. useVector would now be allowed to move from v. (And I must take care to not use v again, since it might have been moved into useVector.)
rvalues: xvalues vs prvalues
Hereโs another way to get an rvalue:
useVector(std::vector๐ฌ);
Here, the expression std::vectorShare your opinion below! is also an rvalue, and again useVector would be allowed to move from it.
Notice, however, that these are two different types of rvalues. std::move(v) takes an existing object and casts it to an rvalue. That type of rvalue is called an xvalue, or โeXpiring lvalueโ.
On the other hand, std::vector๐ฌ is a prvalue, or โpure rvalueโ. Unlike an xvalue, this expression never referred to an existing object in the first place. People sometimes call this โa temporaryโ, but, as is the main point of this article, thatโs not necessarily true.
A prvalue in itself is not a temporary. A prvalue is not an object. A prvalue just represents โthe idea of the objectโ, and only turns into a temporary when it absolutely needs to. For instance:
std::vector v = std::vectorTell us your thoughts in comments!;
Here, the prvalue std::vector๐ฅ does not turn into a temporary that is then used to initialize v. Rather, the prvalue is used to initialize v directly, just as if youโd written std::vector vWhat do you think?;. No extra temporary is created, and no copies or moves are performed.
Similarly:
void useVector(std::vector v);
useVector(std::vector๐ฅ);
Here, useVector takes its parameter by value. std::vectorTell us your thoughts in comments! never turns into a temporary, the prvalue expression is instead used to initialize the parameter v directly, just like in the previous example. No extra temporary is created, and no copies of moves are performed.
Temporary materialization
However, if useVector takes its parameter by reference:
void useVector(const std::vector& v);
useVector(std::vector{1,2,3});
Now, the reference parameter v needs some object to bind to, and std::vector{1,2,3} actually turns into a temporary object that v can bind to. This is called โtemporary materializationโ.
Return values
A function call that returns by value is also a prvalue 1. So, given this definition of getVector() and a call to it:
std::vector getVector();
std::vector v = getVector();
Here, the call getVector() is a prvalue which initializes v directly. There is no temporary that is then copied/moved into v. (There might be a copy involved in the return statement inside getVector(), but thatโs a story for the next article.)
Conclusion
The point is that a prvalue only materializes into a temporary as a very last resort, avoiding unnecessary copies or moves. Until it needs to materialize, it only represents โthe idea of the objectโ, i.e. what the object would be when it materializes into a temporary or is used to initialize something.
It is important to note that this has nothing to do with optimization. There is no temporary std::vector to optimize away in the first place, thereโs just the prvalue, just the โidea of the objectโ. And then that idea of an object can materialize into an actual object if needed.
Footnotes
Discover more from C++ on a Friday
Subscribe to get the latest posts sent to your email.
{๐ฌ|โก|๐ฅ} {What do you think?|Share your opinion below!|Tell us your thoughts in comments!}
#๏ธโฃ #prvalue #temporary #Friday
๐ Posted on 1762491513
