- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- A Tour of C99
- C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The
shared_ptrClass - The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The constexpr Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: export, Exception Specification and register
- The Rejection of the Unified Function Syntax Proposal
- Rvalue References as Object Members
- C++0x Concurrency
- The Reflecting Circle New
- We Have Mail New
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
The rvalue Reference Proposal, Part I
Last updated Oct 13, 2006.
Without exaggeration, the recent proposal to add a new type of references called rvalue references is the most significant core language change since the ratification of ISO C++ in 1998. In the first part of this series I introduce rvalue references and show their usefulness in the implementation of move semantics.
Rvalue References
Document N1690 proposes that rvalue references, a new type of references, be added to C++. Rvalue reference binds to rvalues even if not const qualified. Rvalue references enable programmers to:
- Eliminate unnecessary expensive copies of objects, thereby facilitating the implementation of move semantics.
- Solve major usability problems with generic forwarding utilities, enabling users to implement what is known as perfect forwarding.
- Solve usability problems in components where binding an rvalue to a non-const reference is not a logical error.
Before discussing move semantics, let’s look at the syntax of the new reference type. An rvalue reference to C is declared as C&& . To distinguish an rvalue reference from the existing reference C&, the latter is now termed an lvalue reference.
rvalue references behave just like the existing lvalue references except that they can bind to an rvalue:
C c; C& rc=c; //ordindary lvalue reference C&& rrc=C(); //OK, bind a temporary to an rvalue reference C& illegal = C(); //compilation error
Overloading and Overload Resolution
An rvalue reference and an lvalue reference are distinct types. Therefore, you may declare overloaded versions of the same function that differ in their reference arguments:
void f(const A& a); // #1 lvalue reference void f(A&& a); // #2 rvalue reference
The overload resolution rules are:
- Rvalues will prefer rvalue references. lvalues will prefer lvalue references.
- CV qualification conversions are secondary to rvalue/lvalue conversions.
- rvalues can still bind to a const lvalue reference (e.g., const A&), unless there is a more attractive rvalue reference in the overload set.
- lvalues can bind to an rvalue reference, but will prefer an lvalue reference if available.
- The rule that a more cv-qualified object can not bind to a less cv-qualified reference stands both for lvalue and rvalue references.
Examples:
struct A {};
A f();
const A cf();
A a;
const A ca;
f(a); // calls #1
f(ca); // calls #1
f(source()); // calls #2
f(const_source()); // calls #1
The first f() call prefers the lvalue reference (#1) because the argument a is an lvalue. lvalue to rvalue conversion is a poorer match than A& -> const A& conversion. The second f() call is an exact match for #1. The third f() call is an exact match for #2. The fourth f() call can’t bind to #2 because const A&& to A&& conversion isn’t permitted. It calls #1 via an rvalue to lvalue conversion.
Move Semantics
The primary reason for adding rvalue references is move semantics. Unlike the well-known concept of copying, moving means that a target object pilfers the resources of the source object, instead of reduplicating those resources or sharing them "Why would anyone want that?" you’re probably asking. In most cases, you really want the ordinary copy semantics. However, in some cases making a copy of an object is both expensive and unnecessary. C++ already implements move semantics in several places:
- auto_ptr
- Named Return Value Optimization
In the case of auto_ptr assigning or copy constructing (move-constructing, actually) an auto_ptr object pilfers the source object, transferring its resources to the target object. After the execution of the following code snippet:
auto_ptr <int> a(new int); auto_ptr<int> b (a); //transfer resource ownership from a to b
b has become the new owner of the resource that a acquired during its initialization, whereas a has relinquished its ownership of that resource.
Moving versus Copying
To assess the potential performance gains of move semantics, let’s look at string swapping. A naïve implementation would look like this:
void swapstr(string &a, string & b)
{
string temp = a;
a=b;
b=temp;
}
Copying a string object entails the allocation of raw memory, subsequent copying the characters from the source string to the target etc. By contrast, an implementation that moves strings is more efficient:
void moveswapstr(string &a, string & b)
{
//pseudo code, but you get the idea
size_t sz=a.size();
const char *p= a.data();
//move b’s resources to a
a.setsize(b.size());
a.setdata(b.data());
//move a’s former resources to b
b.setsize(sz);
b.setdata(p);
}
Instead of allocating raw memory dynamically, copying characters from the source to the target object and setting the size value, a move operation merely swaps the memory addresses and the sizes of the two strings.
Fortunately, specialized versions of swap() in the Standard Library are already implemented according to this idiom so you don’t have to rewrite it. However, the point is clear: moving is can be dramatically faster than copying.
Rvalue references facilitate the implementation of move semantics. For example, it enables implementers to add new overloaded versions of an assignment operator and move-constructor that are more efficient than the traditional copy assignment operator and copy constructor:
class string
{
public:
// copy semantics
string(const string& s);
string& operator=(const string& s);
// move semantics
string(string&& s);
string& operator=(string&& s);
// ...
};
The move overloaded versions are automatically called when the argument is an rvalue. Similarly, a function may return an rvalue reference. A call to such a function is an rvalue:
int & f()
{
return *new int;
}
f()=5;
int&& g()
{
return 6;
}
int n=g(); //OK
g()=n; //error, lvalue expected
In the second part I will discuss forwarding and show how rvalue references enable the implementation of perfect forwarding.


Account Sign In
View your cart