Part 1 of this series covered lambdas, auto, and static_assert.
Today, I’m going to talk about rvalue references, which enable two different things: move semantics and perfect forwarding. This post will be long, because I’m going to explain how rvalue references work in great detail. They’re initially very confusing because they distinguish lvalues from rvalues, which very few C++98/03 programmers are extensively familiar with.
Fear not, for using rvalue references is easy, much easier than it initially sounds. Implementing either move semantics or perfect forwarding in your own code boils down to following simple patterns, which I will demonstrate. And it’s definitely worth learning how to use rvalue references, as move semantics can produce order of magnitude performance improvements, and perfect forwarding makes writing highly generic code very easy.
lvalues and rvalues in C++98/03
In order to understand rvalue references in C++0x, you must first understand lvalues and rvalues in C++98/03.
The terminology of “lvalues” and “rvalues” is confusing because their history is confusing. (By the way, they’re just pronounced as “L values” and “R values”, although they’re written as single words.) These concepts originally came from C, and then were elaborated upon by C++. To save time, I’ll skip over their history, including why they’re called “lvalues” and “rvalues”, and I’ll go directly to how they work in C++98/03. (Okay, it’s not a big secret: “L” stands for “left” and “R” stands for “right”. But the concepts have evolved since the names were chosen, and the names aren’t very accurate anymore. Instead of going through the whole history lesson, you can consider the names to be arbitrary like “up quark” and “down quark”, and you won’t lose anything.)
C++03 3.10/1 says: “Every expression is either an lvalue or an rvalue.” It’s important to remember that lvalueness versus rvalueness is a property of expressions, not of objects.
Lvalues name objects that persist beyond a single expression. For example, obj , *ptr , ptr[index] , and ++x are all lvalues.
Rvalues are temporaries that evaporate at the end of the full-expression in which they live (“at the semicolon”). For example, 1729 , x + y , std::string(“meow”) , and x++ are all rvalues.
Notice the difference between ++x and x++ . If we have int x = 0; then the expression x is an lvalue, as it names a persistent object. The expression ++x is also an lvalue. It modifies and then names the persistent object. However, the expression x++ is an rvalue. It copies the original value of the persistent object, modifies the persistent object, and then returns the copy. This copy is a temporary. Both ++x and x++ increment x, but ++x returns the persistent object itself, while x++ returns a temporary copy. That’s why ++x is an lvalue, while x++ is an rvalue. Lvalueness versus rvalueness doesn’t care about what an expression does, it cares about what an expression names (something persistent or something temporary).
If you want to build up intuition for this, another way to determine whether an expression is an lvalue is to ask “can I take its address?”. If you can, it’s an lvalue. If you can’t, it’s an rvalue. For example, &obj , &*ptr , &ptr[index] , and &++x are all valid (even though some of those expressions are silly), while &1729 , &(x + y) , &std::string(“meow”) , and &x++ are all invalid. Why does this work? The address-of operator requires that its “operand shall be an lvalue” (C++03 5.3.1/2). Why does it require that? Taking the address of a persistent object is fine, but taking the address of a temporary would be extremely dangerous, because temporaries evaporate quickly.
The preceding examples ignore operator overloading, which is convenient syntax for a function call. “A function call is an lvalue if and only if the result type is a reference.” (C++03 5.2.2/10) Therefore, given vector<int> v(10, 1729); , v[0] is an lvalue because operator[]() returns int& (and &v[0] is valid and useful), while given string s(“foo”); and string t(“bar”); , s + t is an rvalue because operator+() returns string (and &(s + t) is invalid).
Both lvalues and rvalues can be either modifiable (non-const) or non-modifiable (const). Here are examples:
string one(“cute”);
const string two(“fluffy”);
string three() { return “kittens”; }
const string four() { return “are an essential part of a healthy diet”; }
one; // modifiable lvalue
two; // const lvalue
three(); // modifiable rvalue
four(); // const rvalue
Type& binds to modifiable lvalues (and can be used to observe and mutate them). It can’t bind to const lvalues, as that would violate const correctness. It can’t bind to modifiable rvalues, as that would be extremely dangerous. Accidentally modifying temporaries, only to have the temporaries evaporate along with your modifications, would lead to subtle and obnoxious bugs, so C++ rightly prohibits this. (I should mention that VC has an evil extension that allows this, but if you compile with /W4 , it warns when the evil extension is activated. Usually.) And it can’t bind to const rvalues, as that would be doubly bad. (Careful readers should note that I’m not talking about template argument deduction here.)
const Type& binds to everything: modifiable lvalues, const lvalues, modifiable rvalues, and const rvalues (and can be used to observe them).
A reference is a name, so a reference bound to an rvalue is itself an lvalue (yes, L). (As only a const reference can be bound to an rvalue, it will be a const lvalue.) This is confusing, and will be an extremely big deal later, so I’ll explain further. Given the function void observe(const string& str) , inside observe()‘s implementation, str is a const lvalue, and its address can be taken and used before observe() returns. This is true even though observe() can be called with rvalues, such as three() or four() above. observe(“purr”) can also be called, which constructs a temporary string and binds str to that temporary. The return values of three() and four() don’t have names, so they’re rvalues, but within observe(), str is a name, so it’s an lvalue. As I said above, “lvalueness versus rvalueness is a property of expressions, not of objects”. Of course, because str can be bound to a temporary which will evaporate, its address shouldn’t be stored anywhere where it could be used after observe() returns.
Have you ever bound an rvalue to a const reference and then taken its address? Yes, you have! This is what happens when you write a copy assignment operator, Foo& operator=(const Foo& other) , with a self-assignment check, if (this != &other) { copy stuff; } return *this; , and you copy assign from a temporary, like Foo make_foo(); Foo f; f = make_foo(); .
At this point, you might ask, “So what’s the difference between modifiable rvalues and const rvalues? I can’t bind Type& to modifiable rvalues, and I can’t assign things (etc.) to modifiable rvalues, so can I really modify them?” This is a very good question! In C++98/03, the answer is that there’s a slight difference: non-const member functions can be called on modifiable rvalues. C++ doesn’t want you to accidentally modify temporaries, but directly calling a non-const member function on a modifiable rvalue is explicit, so it’s allowed. In C++0x, the answer changes dramatically, making move semantics possible.
Congratulations! Now you have what I call “lvalue/rvalue vision”, the ability to look at an expression and determine whether it’s an lvalue or an rvalue. Combined with your “const vision”, you can precisely reason that given void mutate(string& ref) and the definitions above, mutate(one) is valid, while mutate(two), mutate(three()), mutate(four()), and mutate(“purr”) are invalid, and all of observe(one), observe(two), observe(three()), observe(four()), and observe(“purr”) are valid. If you’re a C++98/03 programmer, you already knew which of these calls were valid and which were invalid; your “gut feeling”, if not your compiler, would have told you that mutate(three()) was bogus. Your new lvalue/rvalue vision tells you precisely why (three() is an rvalue, and modifiable references can’t be bound to rvalues). Is that useful? To language lawyers, yes, but not really to normal programmers. After all, you’ve gotten this far without knowing all of this stuff about lvalues and rvalues. But here’s the catch: compared to C++98/03, C++0x has vastly more powerful lvalue/rvalue vision (in particular, the ability to look at an expression, determine whether it’s a modifiable/const lvalue/rvalue, and do something about it). In order to use C++0x effectively, you need lvalue/rvalue vision too. And now you have it, so we can proceed!
the copying problem
C++98/03 combines insanely powerful abstraction with insanely efficient execution, but it has a problem: it’s overly fond of copying. Things with value semantics behave like ints, so copying a thing doesn’t modify the source, and the resulting copies are independent. Value semantics are great, except that they tend to lead to unnecessary copies of heavy objects like strings, vectors, and so forth. (“Heavy” means “expensive to copy”; a million-element vector is heavy.) The Return Value Optimization (RVO) and Named Return Value Optimization (NRVO), where copy constructors are elided in certain situations, help to alleviate this problem, but they don’t remove all unnecessary copies.
The most unnecessary copies are those where the source is about to be destroyed. Would you photocopy a sheet of paper and then immediately throw away the original, assuming that the original and the photocopy are identical? That would be wasteful; you should keep the original and not bother with the photocopy. Here’s what I call “the killer example”, derived from one of the Standardization Committee’s examples (in N1377). Suppose that you have a bunch of strings, like this:
string s0(“my mother told me that”);
string s1(“cute”);
string s2(“fluffy”);
string s3(“kittens”);
string s4(“are an essential part of a healthy diet”);
And that you concatenate them like this:
string dest = s0 + ” ” + s1 + ” ” + s2 + ” ” + s3 + ” ” + s4;
How efficient is this? (We’re not worrying about this specific example, which executes in microseconds; we’re worrying about its generalization, which occurs throughout the entire language.)
Each call to operator+() returns a temporary string. There are 8 calls to operator+() , so there are 8 temporary strings. Each one, upon its construction, performs a dynamic memory allocation and copies all of the characters that have been concatenated so far, and later, upon its destruction, performs a dynamic memory deallocation. (If you’ve heard of the Small String Optimization, which VC performs in order to avoid dynamic memory allocations and deallocations for short strings, it’s defeated here by my carefully chosen and sufficiently long s0 , and even if it applied, it couldn’t avoid the copying. If you’ve heard of the Copy-On-Write “optimization”, forget about it – it doesn’t apply here, and it’s a pessimization under multithreading, so Standard Library implementations don’t do it anymore.)
In fact, because every concatenation copies all of the characters that have been concatenated so far, this has quadratic complexity in the number of concatenations. Yuck! This is extraordinarily wasteful, which is especially embarrassing for C++. Why is this happening, and what can we do about it?
The problem is that operator+() , which takes two const string& or one const string& and one const char * (there are other overloads, which we aren’t using here), can’t tell whether it’s being fed lvalues versus rvalues, so it always has to create and return a new temporary string . Why do lvalues versus rvalues matter?
When evaluating s0 + ” “ , it’s absolutely necessary to create a new temporary string . s0 is an lvalue, naming a persistent object, so we can’t modify it. (Someone would notice!) But when evaluating (s0 + ” “) + s1 , we could simply append s1‘s contents onto our first temporary string, instead of creating a second temporary and throwing the first temporary away. This is the key insight behind move semantics: because s0 + ” “ is an rvalue, an expression referring to a temporary object, no one else in the entire program can observe that temporary object. If we could detect that expression as being a modifiable rvalue, we could then proceed to modify the temporary object arbitrarily, without anyone else noticing. operator+() isn’t “supposed to” modify its arguments, but if they’re modifiable rvalues, who cares? In this manner, each call to operator+() can append characters onto a single temporary string . This completely eliminates the unnecessary dynamic memory management and unnecessary copying, leaving us with linear complexity. Yay!
Technically speaking, in C++0x, each call to operator+() still returns a separate temporary string . However, the second temporary string (from evaluating (s0 + ” “) + s1 ) is constructed by stealing the memory owned by the first temporary string (from evaluating s0 + ” “ ) and then appending s1‘s contents onto that memory (which may trigger an ordinary geometric reallocation). “Stealing” consists of pointer twiddling: the second temporary copies and then nulls out the first temporary’s internal pointer. When the first temporary is eventually destroyed (“at the semicolon”), its pointer is null, so its destructor does nothing.
In general, being able to detect modifiable rvalues allows you to engage in “resource pilfering”. If the objects referred to by modifiable rvalues own any resources (such as memory), you can steal their resources instead of copying them, since they’re going to evaporate anyways. Constructing from or assigning from modifiable rvalues by taking what they own is generically referred to as “moving”, and moveable objects have “move semantics”.
This is extremely useful in many places, such as vector reallocation. When a vector needs more capacity (e.g. during push_back()) and undergoes reallocation, it needs to copy elements from

PingBack from http://www.clickandsolve.com/?p=3267
And people say C++ is complex 😉
I wonder how many people will use this additional capability…. I won’t be one of them, but hopefully it’ll be useful for others.
Mike
I’m very excited about rvalue references. I can think of a number of places they will prove useful.
I’m a longtime C++ developer (20 years), and I recently started working in C#, and in Java before that.
I am beginning to develop the opinion that C++ is being crushed under its own weight. By that I mean that the language and libraries have become so complicated that the learning curve to achieve proficiency is way too high. That causes a large number of C++ programmers to not be able to achieve proficiency in the language, as well as other developers to outright avoid the language because of its complexity.
And at the end of the day, while the complexity in C++ may be an interesting intellectual challenge, and it may be necessary in order to support evolution of the language in its current form, one has to really whether this approach makes any sense considering the "big picture." For example, what problems are significantly easier to solve in C++ compared to C#? C# has a learning curve just a fraction of C++, C# is much safer than C++, it is also much more productive than C++.
The only potential benefit I see to C++ is its cross-platform abilities and its potential performance benefits relative to C#. But since most of us are actually programming Windows apps in C++ on pretty fast hardware, is this really any benefit at all?
Personally, I am not optimistic about the future of C++, although it is a language that I really enjoy(ed) and invested a lot of time learning. I just feel that any new project that I personally approach now or in the future, I would find other languages much more compelling.
[Mike Diack]
> I wonder how many people will use this additional
> capability…. I won’t be one of them, but
> hopefully it’ll be useful for others.
Virtually everyone should be writing move constructors and move assignment operators.
> I wonder how many people will use this additional
> capability…. I won’t be one of them, but
> hopefully it’ll be useful for others.
This is my favourite C++0x feature so far – anyone writing moderately large C++ code using the STL should see big perf wins from this and it is so easy to use. You don’t need to understand this article to use it, but this is a great article all the same. Thanks.
@ Mike
> I wonder how many people will use this additional
> capability…. I won’t be one of them, but
> hopefully it’ll be useful for others.
You will be using it indirectly, if nothing else – the standard C++ library objects will, I’m sure, have move semantics implemented for them. The potential performance benefits make that highly likely.
I understand that MS is just implementing the standards, and not really creating them, so they should be commended for that. I just question the direction the standard is taking.
I concur with comments above about C++’s future. The template programming model in C++ has gotten way out of hand. I thought it was out of hand 10 yrs ago, but now, it’s waaay waaay out of hand. It’s a perfect example of Write Only Code. You can write it, but no one else can understand what you did, including perhaps yourself just a few minutes later. And god forbid you misplace a & or two. You could spend days and weeks, and longer trying to figure out what’s wrong. This is very poor language design, IMHO. Sure, it’s intellectually stimulating exercise, but I question the productivity of it, indeed, the sanity of it. Surely there is a better way.
I’ve been a long time fan of C++, having invested over 20 yrs in it. But when STL came out in the early nineties or whenever it was, I took one look at it, and thought, "You’ve got to be kidding me." And now, it’s even worse. I shake my head and wonder about the fact that the C++ designers have still yet to tackle C++’s main problem, and that is its antiquated header file mechanism. Really, that’s so 1970’s. Couldn’t we move on from that? Having to including thousands upon thousands of lines of template gibberish just to access a simple collection class, for example, is adding insult to injury. Why not spend just a little time on moving the language to a more modern mechanism for referencing other modules, such as in C# and Java.
I’ve dabbled with C#, but to me it’s fatal flaw is lack of deterministic destruction. So I stick with C++, but I only use templates in very simplistic ways and sparingly. I avoid STL like the plague. I’d rather have to hand code and duplicate what would otherwise be templated classes and algorithms, and be able to read and understand what was written, than try to navigate through the C++ template thickets.
To me, when I scan through an STL header file, it might as well be a sheet of lead. Very little understanding can get through one of those files.
I long for a language that combines the best of C++ (runtime efficiency with moderately high level abstraction coupled with low-level access), with the smoothness and slickness of C# (better GUI support, IDE support, slick modern features, but without the frustrating non-deterministic destructors design that was imho a big big mistake.) C++/CLI is almost that, but even MS seems to treat that language as for limited interop use.
Commenters above do seem to get the point of C++. Quoting from the article: "[C++] combines insanely powerful abstraction with insanely efficient execution".
Today’s C++ has a very specific purpose. Its complexity is primarily a consequence of its underlying philosophy: "don’t pay for what you don’t use", and of its backward-compatibility with C. If that’s of no interest to you then you should *not* use C++. There are other cross-platforms languages around, that are easier to learn and arguably more productive, like Java or Python.
You must realize that C++ design is primarily a consequence of its insane requirements, and for those requirements, it’s still the best language around.
I don’t want this to descend into a flame war.
As I tried to make clear earlier. I’m not disputing the usefulness of this for some people, but I suspect an equally large number of people won’t (knowingly anyway) make any use of it. That’s not to belittle its usefulness.
However surely no one would deny that such syntax is becoming increasingly arcane – using templates anyway is moderately difficult…
But I’m glad it’s useful for some people.
Mike
Thanks for the article. As for the development of C++ I think this is the path to take. The design goals for C++ should be to create a language that is as fast as C but have most/all of the features of other languages (through the language itself or libraries). If ‘fast enough’ is fast enough you have plenty of languages to choose from but in many cases there is no such thing as ‘fast enough’ and then C++ is your only option if you want object orientation, templates etc etc.
Thanks for the nice article.
Alongside with the concepts, it is my favorite C++0x feature and I’m looking forward to using it.
<williamshatnervoice>
eyes…..bleeding
brain….mush
must…..sleep
</williamshatnervoice>
@Mike: > As I tried to make clear earlier. I’m not disputing the usefulness of this for some people
I think you’re missing the point, this *is* useful to all people using STL, e.g. std::vector<std::string>, which is IMHO the only reasonable way to program in C++ (the using STL way). You don’t have to understand this, you don’t have to explicitly use this. Use STL, enjoy the performance boost and be happy!
Seriously, this makes it possible to use std::vector<std::vector<std::string>> without bringing your machine to its knees.
@Tom: > And at the end of the day, while the complexity in C++ may be an interesting intellectual challenge
It surprises me that a long-time C++-programmer doesn’t realize that this is mainly a feature for use in library-code. It’s mostly transparent to client-code which will just silently benefit from it.
I’m a big fan of C++, too and I definitely welcome rvalue references because it enables elegant resource management!
But I also agree with Mike that C++ is really painful to read at times, especially the metaprogramming stuff is mind-boggling at least and there’s no way to step through runtime-like. And the inclusion model could be definitely better.
On the other hand – why do you scan through an stl header file? You also don’t read the source code for a windows api function but rather read the documentation on how to use it.
Templates are complex but how would you do it differently? Even C# has generics and generic programming requires generic thinking, which is inherently complex. Better documentation with concrete examples would be helpful, though.
The good old news is that C++ was designed with programmers’ freedom in mind, and that’s what I like about C++ – I have control over what I can do and what I’m able to do.
Whether other programmers can understand what I wrote is not the job of the language so much, you can write in every language code that is difficult to grasp, that’s my responsibility.
to off-topic commenters; i for one didn’t find this hard at all – as Stephan showed, it’s mostly about adding a few lines alongside other copy/assignment operators in existing classes; and as others pointed out, this will be transparent when using STL classes.
if you don’t like C++ so be it but please don’t come pollute technical articles with useless whines.
to Stephan; thanks a lot for your article. i really enjoyed the first part and i was looking forward to this one in order to fully comprehend what was behind "rvalue references", std::move and friends. i didn’t do any other research on the subject, simply waited for your article and it proved to be the perfect source of info i was waiting for!
Overall, a touch arcane but not too bad. For library code it can provide a good performance boost, I give it a careful thumbs up.
IMHO performance + flexibility are substantial differentiators between C++ and other many other languages. I personally wish the next few cycles of VC++ would focus/integrate more things important to C++ apps: performance (improvements & measurement), reliability (memory/handle leak detection; built-in error/crash reporting),
quality (static code analysis: Win32/MFC/STL), and updated/improved libraies (MFC/STL)
When’s the next CTP?
Is MFC to be updated to leverage perf benefits of Rvalue References?
I agree, better static analysis (boost generates a lot or warnings there). Include graph complexity would be great, some way to easily identify unnecessary or redundant includes.
When’s the next installment of this blog series?
Please don’t get me wrong. I love C++ – Damien Watkins knows that from the phone chat I had with him!
Mike
Quick plug: Give Gimpel’s PC-Lint a try as a good static analysis tool. I love it.
Mike
[Stuart Dootson]
> the standard C++ library objects will, I’m sure, have move semantics implemented for them.
> The potential performance benefits make that highly likely.
We’re definitely adding support for rvalue references to the C++ Standard Library in VC10.
[BF]
> But when STL came out in the early nineties or whenever it was,
> I took one look at it, and thought, "You’ve got to be kidding me."
The STL is the best thing about C++!
> To me, when I scan through an STL header file, it might as well be a sheet of lead.
You’re not supposed to look at the STL’s implementation. (Yes, really!) It’s perfectly usable if you look at its interface, as documented in the Standard, etc. The interface is very clean, while the implementation is very complicated. (This is because the STL has to be extremely general, and implements high-powered algorithms and data structures in their own right – for example, deque and map are inherently complicated, not to mention regex.)
[Andreas]
> Seriously, this makes it possible to use std::vector<std::vector<std::string>> without bringing your machine to its knees.
Note that VC8/9’s Swaptimization (which I’ve blogged about at length) already made vector<vector<string> > reallocation cheap. The good news is that move semantics supersede the Swaptimization (which we’ve ripped out in VC10) and further improve performance.
[Z]
> it’s mostly about adding a few lines alongside other copy/assignment operators in existing classes
Yep. This post was long because I didn’t want to just say "here, follow these patterns, and they’ll magically work". I could say that to beginners learning C++0x from scratch, but not to established C++98/03 programmers who have the ability, right, and responsibility to understand what’s really happening.
> to Stephan; thanks a lot for your article.
Thank you for reading it.
[longtime c++/mfc dev]
> performance (improvements & measurement)
Move semantics in the language and libraries, the Concurrency Runtime and Parallel Patterns Library, lambdas (which are more efficient than library solutions like bind() and mem_fn()), and so forth in VC10 should feed your hunger for performance.
> reliability (memory/handle leak detection; built-in error/crash reporting)
The best way to deal with leaktrocity and crashtrocity is to avoid them in the first place. For the former, shared_ptr provides the missing piece of the puzzle.
> Is MFC to be updated to leverage perf benefits of Rvalue References?
In some places, yes. We’ve already added move constructors and move assignment operators to CComPtr, CComBSTR, and CAdapt.
[JK]
> When’s the next installment of this blog series?
I definitely have more material for "C++0x Features in VC10". (I haven’t even covered the libraries yet, despite being a library developer!) I don’t have a timeframe for Part 3, but writing it certainly won’t take me as long as Part 2.
I’m super excited about all of the new things that you are doing with VS 2010 for C++. For awhile there I thought MS was going to leave us for dead, but, then you went with VS 2008 and blew past my previously favorite KDE, gave MFC a super breath of fresh air with the Fluent stuff, and all of a sudden, the SDK world is alive and well in Windows. Detractors of MFC really need to just use the wizard and create the sample application with the Office 2007 look for the user interface. It’s just amazing. It looks fantastic, is very functional, and above all, its pretty damn fast.
You guys are kicking ass, and the world is going to know it. Keep up the good work, and thank you for the inspiration!
My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. John Kilmister has created a XAML for WPF Cheat Sheet and it is available for download (.pdf). Greg Duncan posted a link to the WPF
[Mike]
> Quick plug: Give Gimpel’s PC-Lint a try as a good static analysis tool. I love it.
PC-Lint is good stuff with focus on C++ But, a combined analysis on C++ and Win32 (call analysis, usage pattern analysis) would be most excellent – a true product differentiator? or just pie in the sky?
Can you fix your CSS? People on WinXP don’t have ‘Consolas’ installed by default. At least fall back to a generic font-family (i.e. monospace) for source-code. Otherwise I see ‘Times New Roman’ (browser default) for your snippets. Yuck.
And the previous blogpost had CSS referencing the literal font ‘sans-serif’ which naturally doesn’t exist (it should *not* have quotes), so the generic font family ‘sans-serif’ was not being used. Aka more ugly fonts.
There is a change in semantics being discussed in the C++ committee ("A Safety Problem with RValue References (and what to do about it)").
Is VC10 going to have the right semantics? (whichever is chosen)
Or will Microsoft end up releasing a compiler with pre-standard semantics?
Sorry if this is addressed somewhere in your post. I’m still halfway thru it. 😉
[ikk]
> There is a change in semantics being discussed in the C++ committee
I mentioned that at the end of my post.
> Is VC10 going to have the right semantics? (whichever is chosen)
No promises, but I talked to JonCaves, and he said that the front-end changes would be easy. Similarly, the library changes would be easy. The hardest part would be updating our tests. Magic 8 Ball says: Outlook good.
Jonathan also said that this paper would be discussed at the next meeting.
Thank you STL for the great article.
One application of move semantics that you didn’t mention occurs to me because I used to teach C++. One thing that beginners want to do, because it comes naturally is declare something like this:
std::string FunctionThatProducesAStringValue();
Why wouldn’t you? It is exactly how you would declare this:
int FunctionThatProducesAnIntegralValue();
But because we are experienced C++ programmers we know better and have to explain to users why this isn’t efficient and how to do it like this:
void FunctionThatProducesAStringValue(std::string&);
However, with move semantics, the first declaration is no longer inefficient. Since this is a more natural API in man cases this represents a major win for library API designers and users.
To me this is an example of what the committee is trying to do. To preserve backward compatibility, they can’t remove anything from the language, but they can still find ways to simplify by addition.
Commenters that believe this is complicating the language are missing the point completely. Here is the burden distribution:
Committee/language implementor: New complication to deal with
Library writers: Moderate, but straight-forward
increase in work
Library users: Libraries are faster with no code
change
Libraries have more useful APIs
without loss of efficiency
Software users: Performance increase without
loss of reliability or delays
Kudos to the committee and to language and library implementors for doing us a solid on this one.
I definitely want to see more C++ blog posts in the future.
Jon Kalb: The first declaration wasn’t inefficient to begin with, as long as the caller only used the return value to construct a new string (RVO/NRVO are pretty dependable) or swap with an existing string, and avoided the assignment operator. But you’re right, placing the burden on the caller to always do the right thing is rarely a good design.
Hey, well done once again!
I haven’t finished reading this, in fact I only started, but I have a noobie question.
You say <<another way to determine whether an expression is an lvalue is to ask "can I take its address?">>
My intuitive test for lvalue-ness is, "If you can assign something to it, it’s an lvalue". Is this incorrect then, even in C++98/03?
Thanks
[pooh]
> My intuitive test for lvalue-ness is, "If you can assign something to it, it’s an lvalue". Is this incorrect then, even in C++98/03?
Yes.
const int c = 299792458; // c is a const lvalue
c = 300000000; // won’t compile
You’ll notice that I carefully avoided mentioning "lvalue"’s derivation from "what can appear on the left side of an assignment", because that hasn’t been true since const was added to C.
Even the Standard suggests "locator value" as a better expansion than "left value". If I had my way I’d probably call them pvalues and tvalues, for "persistent" and "temporary".
I originally wrote this as an E-mail to a Microsoft-internal mailing list, where I devoted a whole section to explaining the history of lvalues and rvalues in C and C++. This was more confusing than enlightening, and in the worst possible place too (at the beginning, where I am already asking readers to set aside their boredom for a few minutes in exchange for something that will grant them ultimate power). What matters is the current meaning of the terms, not their history, so when I rewrote this for VCBlog I removed the history lesson and devoted more time to demonstrating modifiable/const lvalues/rvalues.
Thank you for another great blog post, Stephan – it’s the reason why this blog is one of those I check daily
In the previous installment of this post series, in comments, I raised the issue of how TR1 classes are handled for VC10. Here’s how it went:
[int19h] As I understand, you’ll be moving all the stuff from TR1 that makes reappearance in C++0x into namespace std. What about the new stuff, such as std::unique_ptr?
[STL] We’re dragging TR1 components into namespace std with using-declarations.
[int19h] Erm… I might be wrong, but isn’t it going to Break Things (for template specialization purposes etc), unless you have "strong using" implemented, and are using it for that purpose?
[STL] That’s a good question. I’ll ask.
Any news on that front?
int19h:
I talked to Dinkumware, and the using-declarations almost certainly affect user specializations. (It’s not the end of the world – you just have to switch which namespace you’re specializing in.) We’re doing it this way because it minimizes the changes to our codebase and the impact on TR1 users (who are more numerous than our zero C++0x users). At some point in the future, we may reverse things (declaring everything in std and dragging selected components into tr1).
Eventually, I’d like to remove TR1 (it differs from C++0x in several ways, and supporting both is more work). However, VC10 will certainly still support TR1.
[Nacsa Sándor, 2009. január 20. – február 12.] Komplett fejlesztő környezet Windows kliens és web alkalmazások
> It’s not the end of the world – you just have to switch which namespace you’re specializing in.
While true, this introduces a potential point of incompatibility between implementations. I’m fairly sure that g++ will have it working correctly straight away, for example, because they have "strong using" already, which allows them to pull the same trick you do entirely transparently for the client.
C and C++ were devised for great performance but some flaws have been around for years. It seems that most of this stuff is fixed in the new Standard which is awesome!!
I’ve been working with containers for a while and the temporaries thing worried me because it really hurt performance. Now It’s definitively solve at last.
From my point of view its a pity that TR1 improvements like smart pointers, bind and function were not release before. They have been around since almost the appearance of the last standard and work just fine with it.
My greetings to Stephen for the article I have learn a lot from it. I’ve been using expressions like
MyType & ob = Function(…);
very often because it used to save the creation of a temporary object without known it breaks the standard. Now it seems that the compiler have been improved enought to make
MyType ob = Function(…);
work in the same way.
To make all my dreams be fullfil for now the libraries team should reimplement the valarray class taking advantage of SSE technology.
Great Job!!
This article cracked me up. Many of us solved these problems years ago and in much more elegant ways. Unfortunately, C++ has largely become an academic language with extremely confusing and contradictory constructs which add little to writing small, fast, efficient code. The reality is that most problems in C++ can be avoided by keeping your code simply and straightforward. For example, anyone who writes:
string result = s1 + " " + s2;
is an idiot. This is true for C# as well. Even writing:
string result = s1;
result += " ";
result += s2;
is dumb and results in poor, bloated performance. Truth is, if all you want is these two strings concatenated together, just use simply string copies and concatenations.
The point is that I see developers using STL and C++ concepts so cavalierly, I wonder why they even bother with C++. If small size and fast operation doesn’t matter, why not use C# or Java or, heaven forbid, VB? If, on the other hand, small size and speed matter than learn to write small, fast code deliberately without having to guess what the C++ compiler will do.
Stephan:
Thanks very much for this great primer on rvalue references.
Among other things, I liked the way you clearly summed up lvalues vs. rvalues:
——————
Lvalueness versus rvalueness doesn’t care about what an expression does, it cares about what an expression names (something persistent or something temporary).
——————
so nice way of programming its interesting i love knowing and reading this program.
Thanks very much for this update with VC++ 10.0, we will move all our components to use this new feature.
Jack
———————————————–
For high quality flow/diagram MFC/C++ Visio 12 Like visualization Source Code, download XD++ at: http://www.ucancode.net
> I’ve been using expressions like
>
> MyType & ob = Function(…);
>
> very often because it used to save the creation of a temporary object
without known it breaks the standard.
Um, surely you know that, more often than not, RVO will kick in anyway so there is no temporary created there, even with today’s compilers?
Will VC10 support variable length array (VLA)? I really need that feature badly. Other C/C++ compilers support VLA.
[morovia]
> Will VC10 support variable length array (VLA)?
No; that is a C99 language feature.
> I really need that feature badly.
Why? C++ has std::vector.
Thanks for the blog, Stephan! Just a few little remarks of mine:
It’s interesting to get to know why morovia wants to have VLA so badly, but it looks like this is indeed recognized as a significant "missing feature" in C++, as "dynarray" is planned to be added to a future version of the Standard C++ Library. http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2008/n2648.html
There’s a tiny little bug regarding the exception-safety of the copy-assignment operator of your remote_integer, at least if "new int(*other.m_p)" might ever throw… Which is highly theoretical, I hope!
FYI, I’ve just submitted a paper that intends to bring back that historical notion of lvalues being allowed at the left side of an assignment, while keeping the rvalues at the right. (As much as reasonable, of course!) Cowritten with Daniel Kruegler: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2819.html
Just my two cents, Niels
[Niels Dekker]
> There’s a tiny little bug regarding the exception-safety of the copy-assignment operator of your remote_integer
Yep, my bad. I should have provided at least the basic guarantee, by setting m_p = NULL after deleting it.
> FYI, I’ve just submitted a paper that intends to bring back that historical notion of lvalues being allowed at the left side of an assignment, while keeping the rvalues at the right.
That appears to be a worthy proposal, but it doesn’t allow "lvalue means left" to be taught. Const lvalues can’t be assigned to.
> That appears to be a worthy proposal
Thank you!
> but it doesn’t allow "lvalue means left" to be taught. Const lvalues can’t be assigned to.
Our proposal certainly isn’t going to make any more const lvalues assignable, so my previous comment was oversimplified. FWIW, certain types /do/ allow assignment to const (both lvalue and rvalue), including std::slice_array and std::indirect_array. We’ve excluded those particular types from the proposal, as they’re typically /intended/ to support assignment to an rvalue.
Yes – I should have clarified that I was talking about built-ins.
[Mike]
> Quick plug: Give Gimpel’s PC-Lint a try as a good static analysis tool. I love it.
Another quick plug:
If you want to use PC Link with Visual Studio then you should look at Visual Lint at
http://www.riverblade.co.uk/
OK, finished. As I said, excellent article. I can’t say I understood everything, but I think I get the idea.
I think it would have been nice to summarise the benefits and common idioms enabled by rvalue refs for mere mortals – and I suspect it would have spared us some flames. I’ll have a stab at it here, please correct me if I’m wrong or I missed any other benefits.
1. If, by means of std::move, you implement move copy ctor and move assignment operator for MyType (and you should), users of that class need not worry ever again about the performance of writing things like
MyType myObj = f();
because move semantics kick in and save you a copy where RVO and NRVO do not – and incidentally behaving in a deterministic manner, unlike NRVO, but I might not be up to date on the subject.
2. Similarly, unnecessary copies of temporary objects in chained expressions are avoided.
3. Most of the standard library is now move-semantics-aware, and therefore having e.g. a standard container (what else?) of MyTypes is more performant when things like reallocations occur.
4. perfect forwarding is now enabled and supported by std::forward – for those who care
Have I been an attentive boy?
Thanks
Hi Stephan, I am a CS graduated student in TsingHwa University in Taiwan. I had read this great artical and learned a lot. Thank you for your great job.
I would like to share it to Taiwan’s CS students and C++ programmer. Can I translate this artical into Traditional Chainese, and post it to some forum(telnet.ptt.cc) in Taiwan and my own blog(endlesschildhood.blogspot.com)? Of cause I will indicate the source of this article.
Thanks for your great work again.
peter.xiau at gmail
I was just wondering if this is a reasonable implementation of a copy assignment operator that gives the strong guarantee?
remote_integer& operator=(const remote_integer& other) {
cout << "Copy assignment operator." << endl;
if (this != &other) {
if (m_p) {
if (other.m_p) {
*m_p = *other.m_p;
} else {
delete m_p;
m_p = NULL;
}
} else {
if (other.m_p) {
m_p = new int(*other.m_p);
}
}
}
return *this;
}
I hope that formats properly.
As a big supporter of C++1x (sorry guys, it’s not coming out this year), I am very happy to see that you guys are implementing these things so quickly. C++1x stands to be one of the fastest-accepted new standards, as MSVC, GCC, EDG, and CodeGear are all implementing various C++1x features, and I’m already using some of them in my own code, and starting to feel annoyed when I can’t (std::tie, I love you).
I also do a fair bit of porting, which brings me to my first point:
> I should mention that VC has an evil extension that allows this, but if you compile with /W4 , it warns when the evil extension is activated.
I can’t help but scream NONONONONONONO. I’m not an expert on what all the warning flags mean (so I could be overreacting here), but somehow I suspect /W4 is not common, and thus that many programmers code assuming this extension is normal, inflicting headaches on people such as myself trying to compile with different compilers. It’s like VC6 all over again.
std::tr1 vs. std is another interesting issue. Once again, I would very much push you guys to implement properly forwarding bind, etc. immediately. Since tr1 will cease (at least as far as my understanding of ISO procedure goes) to be normative when C++1x is release, if you aren’t providing separate options for picking C++1x mode and appropriate macros in the headers (as GCC does), then perhaps you would find it easiest to do this:
namespace std
{
namespace tr1 = ::std;
}
This allows specializations to be present in std or std::tr1. Of course, it gives a couple of other funny results (like std::tr1::tr1::tr1::vector<int> being legal), but if you aren’t going to go the compile-switch route (which I would highly recommend!), this is probably the most elegant solution.
The last complaint is something you’ve probably heard before, but I would just like to reiterate: Please implement C++1x standard attributes. Please. Nothing will hurt adoption of C++1x more than a major compiler leaving out a major feature. You can put all your existing attributes in an attribute-namespace like "ms", and then the entire world will celebrate
One last thing: If VC10 actually implements exception specifications and two-stage name lookup, I will be happy, because those are two useful features (yes, I just called C++ exception specifications useful!) that you sadly don’t have yet. The first is rather minor, as I use it mainly to help debugging, but the second is important – if you look at Boost code you may understand why it is I care so much that compilers implement templates The Right Way. Export would be nice too, but that was a pipe dream 10 years ago and hasn’t changed one bit.
@Sean Hunt
From Stephan’s first article we learn that
"The Standardization Committee hopes that they’ll be finished in 2009, making it C++09; the joke is that if it slips to 2010 or later, the ‘x’ will be hexadecimal."
[pooh]
> As I said, excellent article. I can’t say I understood everything, but I think I get the idea.
Awesome.
> I think it would have been nice to summarise the benefits and common idioms enabled by rvalue refs for mere mortals
I summarized the benefits (performance and genericity) in my introduction. I also clearly identified the common patterns/idioms with my section titles, and bolded the relevant parts of my self-contained examples.
Although I strongly prefer self-contained examples over snippets when explaining anything in detail, I could have presented the relevant parts as snippets in my introduction, followed by the self-contained examples. I’ll keep that in mind for the future.
> I’ll have a stab at it here, please correct me if I’m wrong or I missed any other benefits.
#1: Correct. The RVO and NRVO are applied at the compiler’s discretion; you can see in my examples how I got the compiler to give up and not apply them. Also, the RVO/NRVO apply only to construction, not to assignment.
#2: Correct. Assuming that the operators, etc. in the chain are aware of move semantics.
#3: Correct. Actually, all of the Standard Library will be aware of move semantics. Any deficiencies are bugs.
#4: Correct. Library authors take advantage of perfect forwarding, and library users automatically benefit. This is unlike move semantics where library users have to provide move constructors and move assignment operators for their types in order to get them picked up by the library.
[Yoco Xiao]
> Thank you for your great job.
You’re welcome.
> Can I translate this artical into Traditional Chainese
Yes, that’s fine. Please link to the original article and indicate that your translation is unofficial.
[Ahmed Charles]
> I was just wondering if this is a reasonable implementation of a copy assignment operator that gives the strong guarantee?
Yep. Thanks for writing it up.
[Sean Hunt]
> starting to feel annoyed when I can’t (std::tie, I love you).
VC9 SP1 contains std::tr1::tie(); perhaps you’re talking about another compiler.
>> I should mention that VC has an evil extension that allows this
> I can’t help but scream NONONONONONONO.
I don’t like that extension. (The phrases "abomination" and "enemy of humanity" come to mind.) Hence the "evil".
> I’m not an expert on what all the warning flags mean (so I could be overreacting here), but somehow I suspect /W4 is not common,
VC’s /W4 ("warning level 4") is the rough equivalent of GCC’s -Wall -Wextra . That is, it attempts to provide all of the commonly useful warnings. There are some useful warnings that it doesn’t provide, and some of the warnings that it does provide aren’t very useful, but by and large it’ll find lots of badness and waste little of your time. VC’s /Wall ("all warnings") does what it says on the box: it enables all warnings (some of which are extremely noisy). VC’s headers are /W4-clean but not /Wall-clean.
Everyone should compile with /W4 at a minimum. Although I don’t use IDEs, I believe that devenv defaults to /W3 .
> and thus that many programmers code assuming this extension is normal,
> inflicting headaches on people such as myself trying to compile with different compilers.
Hence the "evil".
> It’s like VC6 all over again.
It’s almost certainly *from* VC6. To be clear, this evil extension is NOT new to VC10 – it’s very old.
> I would very much push you guys to implement properly forwarding bind, etc. immediately.
I’ve already opened a bug to use rvalue references in <functional> (which will also simplify its implementation).
> Since tr1 will cease (at least as far as my understanding of ISO procedure goes) to be normative when C++1x is release
TR1 was never normative; it was not an International Standard.
> Please implement C++1x standard attributes.
Thanks for the request. However, this won’t be implemented in VC10. We really didn’t have time to implement everything (including the feature that I’m drooling over, variadic templates). In particular, attributes weren’t finalized until very recently (they weren’t integrated into the Working Paper as of the N2705 status report).
> One last thing: If VC10 actually implements exception specifications and two-stage name lookup
It won’t, sorry.
>> Will VC10 support variable length array (VLA)?
> No; that is a C99 language feature.
Where do I put in a feature request for C99 support in VC10?
I really don’t want to have to move to mingw (from VC9).
@Peter Harris
Good luck. I’ve requested C99 and they won’t do it. C99 would be a big win for Microsoft.
Part 1 of this series covered lambdas , auto , and static_assert . Part 2 of this series covered rvalue
Visual Studio 2010 Beta 1 introduces a number of exciting new features for the C++ developer as we include
Visual Studio 2010 Beta 1 is now available for download. I’ve recently blogged about how Visual C++ in