Forwarding References
Learn the concept of forwarding references in C++.
We'll cover the following...
Kinds of references in C++11
One of the most important features that were added to the language in C++11 is move semantics, which helps improve performance by avoiding making unnecessary copies. Move semantics are supported by another C++11 feature called rvalue references. Before discussing these, it’s worth mentioning that in C++, we have two kinds of values:
lvalues are values that refer to a memory location; therefore, we can take their address with the
&
operator. lvalues can appear both on the left and right sides of an assignment expression.rvalues are values that are not lvalues. They are defined by exclusion. rvalues do not refer to a memory location, and we can’t take their address with the
&
operator. rvalues are literals and temporary objects and can only appear on the right side of an assignment expression.
Note: In C++11, there are a few other value categories, glvalue, prvalue, and xvalue. Discussing them here would not benefit the current topic. However, we can read more about them on the cppreference website.
References are aliases to already existing objects or functions. Just as we have two kinds of values, in C++11 we have two kinds of references:
lvalue references, denoted with a
&
, such as in&x
, are references to lvalues.rvalue references, denoted with
&&
, such as in&&x
, are references to rvalues.
Let’s look at some examples to understand these concepts better:
struct foo {int data;};void f(foo& v){ std::cout << "f(foo&)\n"; }void g(foo& v){ std::cout << "g(foo&)\n"; }void g(foo&& v){ std::cout << "g(foo&&)\n"; }void h(foo&& v){ std::cout << "h(foo&&)\n"; }foo x = { 42 }; // x is lvaluefoo& rx = x; // rx is lvalue
We have three functions here: f
, which takes an lvalue reference (that is, int&
); g
, which has two overloads, one for an lvalue reference, and one for an rvalue reference (that is, int&&
); and h
, which takes an rvalue reference. We also have two variables, x
and rx
. Here, x
is an lvalue whose type is foo
. We can take its address with &x
. An lvalue is also rx
, which is an lvalue reference whose type is foo&
. Now, let’s see how we can call each of the f
, g
, and h
functions:
f(x); // f(foo&)f(rx); // f(foo&)// f(foo{42}); // error: a non-const reference may only be bound to an lvalue
Note: Uncommenting line 3 will generate an error. ...