Why is Copy constructor called with rvalue - c++

In the below code, even though Account(20, "Dave") at Line2 is rvalue, why is the copy constructor called (Line1), instead of compiler throwing error? In case of normal functions receiving rvalue, if we use lvalue reference as input parameter, compiler throws error.
#include <iostream>
#include <string>
#include <vector>
class Account
{
private:
int num;
std::string name;
public:
Account(int lnum, std::string lname) : num {lnum}, name {lname}
{
std::cout << "\n3arg constr";
}
Account(const Account &a) : Account{a.num, a.name} //Line1
{
std::cout << "\nCopy Constr";
}
};
int main()
{
std::vector<Account> myVec {};
myVec.push_back(Account(20, "Dave")); //Line2
std::cout << std::endl;
}

Yes, rvalues are moved, lvalues are copied. But when there's no according move operation, rvalues are copied as well.
The compiler will synthesize a move constructor only for such class that doesn't define any of its own copy-control members (copy-constructor, copy-assignment, or destructor), and if all the non-static members can be moved.
If a class doesn't have a move operation, the corresponding copy operation will be used, through normal function matching (T&& can convert to const T&).
Unlike copy operations, a move operation won't be implicitly defined as deleted function. A copy is simply used instead.
As for the push_back(). Vector provides guarantees that is something goes wrong in process of the push_back(), the vector, to which we push, will be left unchanged, in the absence of noexcept move constructor for a class, a copy is used instead,

What you have in Account(const Account &a) is an lvalue reference to const. Const lvalue references can bind to rvalues. Quoting the reference (emphasis mine)
Rvalue references can be used to extend the lifetimes of temporary
objects (note, lvalue references to const can extend the lifetimes of
temporary objects too, but they are not modifiable through them):
struct Foo{};
void bar(Foo && f) {}
void baz(Foo const&) {}
void qux(Foo&) {}
int main() {
bar(Foo{}); //rvalue reference binds to rvalue
baz(Foo{}); //const rvalue reference binds to rvalue
//Error: cannot bind non-const lvalue reference of type 'Foo&' to an rvalue of type 'Foo'
// qux(Foo{});
}

Related

Do you have to do std::move on an rvalue, when passing it to another function that expects &&? [duplicate]

I am confused about using std::move() in below code:
If I uncomment line at (2) the output would be: 1 2 3 but if I uncomment line at (1) output would be nothing which means that move constructor of std::vector was called!
Why do we have to make another call to std::move at (1) to make move constructor of std::vector to be called?
What I understood that std::move get the r-value of its parameter so, why we have to get the r-value of r-value at (1)?
I think this line _v = rv; at (2) is more logical and should make std::vector move constructor to be called without std::movebecause rv itself is r-value reference in the first place.
template <class T>
class A
{
public:
void set(std::vector<T> & lv)
{
}
void set(std::vector<T> && rv)
{
//_v = std::move(rv); (1)
//_v = rv; (2)
}
private:
std::vector<T> _v;
};
int main()
{
std::vector<int> vec{1,2,3};
A<int> a;
a.set(std::move(vec));
for(auto &item : vec)
cout << item << " ";
cout << endl;
return 0;
}
Every named object is a Lvalue:
the name of a variable, a function, a template parameter object (since
C++20), or a data member, regardless of type, such as std::cin or
std::endl. Even if the variable's type is rvalue reference, the
expression consisting of its name is an lvalue expression;
vector has two overloads of assignment operator, one for Lvalue reference and another for Rvalue reference.
vector::operator=(const vector&) // copy assignment operator
vector::operator=(vector&&) // move assignment operator
Overload which takes Lvalue reference is called when Lvalue is passed as argument for operator=.
Details here
when a function has both rvalue reference and lvalue reference
overloads, the rvalue reference overload binds to rvalues (including
both prvalues and xvalues), while the lvalue reference overload binds
to lvalues
By std::move(rv); you cast rv - Lvalue to Rvalue reference, and operator= which takes Rvalue reference is called. Otherwise, Lvalue binds to Lvalue reference and vector is copied instead of being moved.

Mixing Rvalue and LValue reference

I'm trying to better understand LValue, RValue, and how std::move works.
I have the following code
#include <string>
class A
{
public:
A() = default;
A(std::string&& aString): myString(std::move(aString)) {}
std::string myString;
};
class B
{
public:
void InitMembers(std::string& aString) { myA = A(std::move(aString));}
private:
A myA;
};
int main()
{
B b;
std::string hello;
b.InitMembers(hello);
}
my questions are:
In void InitMembers(string& aString) { myA = A(std::move(aString));} I understand that I have to use std::move to aString in order to cast aString from an LValue reference to a RValue reference. But I have some doubts regarding the meaning of aString in the InitMember scope. aString is provided as an LValue reference, but in the method scope it's considered as an LValue and that's why I have to use the std::move? Std::move should rely on reference deduction (right?), how does it deduce the type in this case? It will deduce a type "string" o "string&" since aString is provided as a LValue Reference in the method's arguments?
Why do I have to use std::move also in the constructor initializer of A? Shouldn't be enough the fact that aString is an RValue reference, which triggers the move constructor?
Isn't the following implementation good as the one above?
#include <string>
class A
{
public:
A() = default;
A(std::string& aString): myString(std::move(aString)) {}
std::string myString;
};
class B
{
public:
void InitMembers(std::string& aString) { myA = A(aString);}
private:
A myA;
};
int main()
{
B b;
std::string hello;
b.InitMembers(hello);
}
Thanks :)
Concerning
A(std::string&& aString): myString(std::move(aString)) {}
std::string&& denotes an rvalue reference to a std::string. Rvalue references only bind to rvalues (both prvalues and xvalues), so the two possible call sites will be like this:
// assuming this is defined somewhere
std::string f(void); // returns by value, i.e. `f()` is an rvalue
// call site 1
A a1{f()}; // `f()` is an rvalue (precisely a prvalue)
// assuming this
std::string s{"ciao"}; // s is an lvalue
// call site 2
A a2{std::move(s)}; // `std::move(s)` is an rvalue (precisely an xvalue)
// i.e. with `std::move` we turn s into an rvalue argument,
// so it can bind to the rvalue reference parameter
// don't expect s to be the one it was before constructing a2
In either case, what does the constructor do with aString?
Well, aString is an lvalue, because "it has a name" (the actual definition is a bit more complicated, but this is the easiest one to get started with, and it isn't all that wrong after all), so if you use it verbatim, the compiler won't assume it is bound to a temporary and it won't let myString steal it resources.
But you know that aString is bound to a temporary, because you've declared it as std::string&&, so you pass it as std::move(aString) to tell the compiler "treat this is a temporary".
Yes, technically also the compiler knows that aString is bound to a temporary, but it can't std::move it automatically. Why? Because you might want to use it more than once:
A(std::string&& aString) : myString(aString/* can't move this */) {
std::cout << aString << std::endl; // if I want to use it here
}
// yes, this is a very silly example, sorry
As regards
void InitMembers(std::string& aString) { myA = A(std::move(aString));}
aString denotes an lvalue reference to non-const std::string, so you can pass to .InitMembers only non-const lvalues.
Then inside the function you're std::moveing it to tell A's constructor "look, this is a temporary". But that also means that at the call site (b.InitMembers(hello);) you're leaving the input (hello) in a moved-from state, just like the s in the first example above. That's ok, because the caller knows that InitMembers takes its parameter by non-const lvalue reference, so it is aware that the argument they pass can be changed by the call. Just like in the previous example it's the user who's writing std::move around s, so they're supposed to know what they do.
For more details about how std::move works (and std::forward as well), I want to point you to this answer of mine.

c++ : what is the meaning of && [duplicate]

I've been looking into some of the new features of C++11 and one I've noticed is the double ampersand in declaring variables, like T&& var.
For a start, what is this beast called? I wish Google would allow us to search for punctuation like this.
What exactly does it mean?
At first glance, it appears to be a double reference (like the C-style double pointers T** var), but I'm having a hard time thinking of a use case for that.
It declares an rvalue reference (standards proposal doc).
Here's an introduction to rvalue references.
Here's a fantastic in-depth look at rvalue references by one of Microsoft's standard library developers.
CAUTION: the linked article on MSDN ("Rvalue References: C++0x Features in VC10, Part 2") is a very clear introduction to Rvalue references, but makes statements about Rvalue references that were once true in the draft C++11 standard, but are not true for the final one! Specifically, it says at various points that rvalue references can bind to lvalues, which was once true, but was changed.(e.g. int x; int &&rrx = x; no longer compiles in GCC) – drewbarbs Jul 13 '14 at 16:12
The biggest difference between a C++03 reference (now called an lvalue reference in C++11) is that it can bind to an rvalue like a temporary without having to be const. Thus, this syntax is now legal:
T&& r = T();
rvalue references primarily provide for the following:
Move semantics. A move constructor and move assignment operator can now be defined that takes an rvalue reference instead of the usual const-lvalue reference. A move functions like a copy, except it is not obliged to keep the source unchanged; in fact, it usually modifies the source such that it no longer owns the moved resources. This is great for eliminating extraneous copies, especially in standard library implementations.
For example, a copy constructor might look like this:
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
If this constructor were passed a temporary, the copy would be unnecessary because we know the temporary will just be destroyed; why not make use of the resources the temporary already allocated? In C++03, there's no way to prevent the copy as we cannot determine whether we were passed a temporary. In C++11, we can overload a move constructor:
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
Notice the big difference here: the move constructor actually modifies its argument. This would effectively "move" the temporary into the object being constructed, thereby eliminating the unnecessary copy.
The move constructor would be used for temporaries and for non-const lvalue references that are explicitly converted to rvalue references using the std::move function (it just performs the conversion). The following code both invoke the move constructor for f1 and f2:
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
Perfect forwarding. rvalue references allow us to properly forward arguments for templated functions. Take for example this factory function:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
If we called factory<foo>(5), the argument will be deduced to be int&, which will not bind to a literal 5, even if foo's constructor takes an int. Well, we could instead use A1 const&, but what if foo takes the constructor argument by non-const reference? To make a truly generic factory function, we would have to overload factory on A1& and on A1 const&. That might be fine if factory takes 1 parameter type, but each additional parameter type would multiply the necessary overload set by 2. That's very quickly unmaintainable.
rvalue references fix this problem by allowing the standard library to define a std::forward function that can properly forward lvalue/rvalue references. For more information about how std::forward works, see this excellent answer.
This enables us to define the factory function like this:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
Now the argument's rvalue/lvalue-ness is preserved when passed to T's constructor. That means that if factory is called with an rvalue, T's constructor is called with an rvalue. If factory is called with an lvalue, T's constructor is called with an lvalue. The improved factory function works because of one special rule:
When the function parameter type is of
the form T&& where T is a template
parameter, and the function argument
is an lvalue of type A, the type A& is
used for template argument deduction.
Thus, we can use factory like so:
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
Important rvalue reference properties:
For overload resolution, lvalues prefer binding to lvalue references and rvalues prefer binding to rvalue references. Hence why temporaries prefer invoking a move constructor / move assignment operator over a copy constructor / assignment operator.
rvalue references will implicitly bind to rvalues and to temporaries that are the result of an implicit conversion. i.e. float f = 0f; int&& i = f; is well formed because float is implicitly convertible to int; the reference would be to a temporary that is the result of the conversion.
Named rvalue references are lvalues. Unnamed rvalue references are rvalues. This is important to understand why the std::move call is necessary in: foo&& r = foo(); foo f = std::move(r);
It denotes an rvalue reference. Rvalue references will only bind to temporary objects, unless explicitly generated otherwise. They are used to make objects much more efficient under certain circumstances, and to provide a facility known as perfect forwarding, which greatly simplifies template code.
In C++03, you can't distinguish between a copy of a non-mutable lvalue and an rvalue.
std::string s;
std::string another(s); // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(const std::string&);
In C++0x, this is not the case.
std::string s;
std::string another(s); // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(std::string&&);
Consider the implementation behind these constructors. In the first case, the string has to perform a copy to retain value semantics, which involves a new heap allocation. However, in the second case, we know in advance that the object which was passed in to our constructor is immediately due for destruction, and it doesn't have to remain untouched. We can effectively just swap the internal pointers and not perform any copying at all in this scenario, which is substantially more efficient. Move semantics benefit any class which has expensive or prohibited copying of internally referenced resources. Consider the case of std::unique_ptr- now that our class can distinguish between temporaries and non-temporaries, we can make the move semantics work correctly so that the unique_ptr cannot be copied but can be moved, which means that std::unique_ptr can be legally stored in Standard containers, sorted, etc, whereas C++03's std::auto_ptr cannot.
Now we consider the other use of rvalue references- perfect forwarding. Consider the question of binding a reference to a reference.
std::string s;
std::string& ref = s;
(std::string&)& anotherref = ref; // usually expressed via template
Can't recall what C++03 says about this, but in C++0x, the resultant type when dealing with rvalue references is critical. An rvalue reference to a type T, where T is a reference type, becomes a reference of type T.
(std::string&)&& ref // ref is std::string&
(const std::string&)&& ref // ref is const std::string&
(std::string&&)&& ref // ref is std::string&&
(const std::string&&)&& ref // ref is const std::string&&
Consider the simplest template function- min and max. In C++03 you have to overload for all four combinations of const and non-const manually. In C++0x it's just one overload. Combined with variadic templates, this enables perfect forwarding.
template<typename A, typename B> auto min(A&& aref, B&& bref) {
// for example, if you pass a const std::string& as first argument,
// then A becomes const std::string& and by extension, aref becomes
// const std::string&, completely maintaining it's type information.
if (std::forward<A>(aref) < std::forward<B>(bref))
return std::forward<A>(aref);
else
return std::forward<B>(bref);
}
I left off the return type deduction, because I can't recall how it's done offhand, but that min can accept any combination of lvalues, rvalues, const lvalues.
The term for T&& when used with type deduction (such as for perfect forwarding) is known colloquially as a forwarding reference. The term "universal reference" was coined by Scott Meyers in this article, but was later changed.
That is because it may be either r-value or l-value.
Examples are:
// template
template<class T> foo(T&& t) { ... }
// auto
auto&& t = ...;
// typedef
typedef ... T;
T&& t = ...;
// decltype
decltype(...)&& t = ...;
More discussion can be found in the answer for: Syntax for universal references
An rvalue reference is a type that behaves much like the ordinary reference X&, with several exceptions. The most important one is that when it comes to function overload resolution, lvalues prefer old-style lvalue references, whereas rvalues prefer the new rvalue references:
void foo(X& x); // lvalue reference overload
void foo(X&& x); // rvalue reference overload
X x;
X foobar();
foo(x); // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)
So what is an rvalue? Anything that is not an lvalue. An lvalue being
an expression that refers to a memory location and allows us to take the address of that memory location via the & operator.
It is almost easier to understand first what rvalues accomplish with an example:
#include <cstring>
class Sample {
int *ptr; // large block of memory
int size;
public:
Sample(int sz=0) : ptr{sz != 0 ? new int[sz] : nullptr}, size{sz}
{
if (ptr != nullptr) memset(ptr, 0, sz);
}
// copy constructor that takes lvalue
Sample(const Sample& s) : ptr{s.size != 0 ? new int[s.size] :\
nullptr}, size{s.size}
{
if (ptr != nullptr) memcpy(ptr, s.ptr, s.size);
std::cout << "copy constructor called on lvalue\n";
}
// move constructor that take rvalue
Sample(Sample&& s)
{ // steal s's resources
ptr = s.ptr;
size = s.size;
s.ptr = nullptr; // destructive write
s.size = 0;
cout << "Move constructor called on rvalue." << std::endl;
}
// normal copy assignment operator taking lvalue
Sample& operator=(const Sample& s)
{
if(this != &s) {
delete [] ptr; // free current pointer
size = s.size;
if (size != 0) {
ptr = new int[s.size];
memcpy(ptr, s.ptr, s.size);
} else
ptr = nullptr;
}
cout << "Copy Assignment called on lvalue." << std::endl;
return *this;
}
// overloaded move assignment operator taking rvalue
Sample& operator=(Sample&& lhs)
{
if(this != &s) {
delete [] ptr; //don't let ptr be orphaned
ptr = lhs.ptr; //but now "steal" lhs, don't clone it.
size = lhs.size;
lhs.ptr = nullptr; // lhs's new "stolen" state
lhs.size = 0;
}
cout << "Move Assignment called on rvalue" << std::endl;
return *this;
}
//...snip
};
The constructor and assignment operators have been overloaded with versions that take rvalue references. Rvalue references allow a function to branch at compile time (via overload resolution) on the condition "Am I being called on an lvalue or an rvalue?". This allowed us to create more efficient constructor and assignment operators above that move resources rather copy them.
The compiler automatically branches at compile time (depending on the whether it is being invoked for an lvalue or an rvalue) choosing whether the move constructor or move assignment operator should be called.
Summing up: rvalue references allow move semantics (and perfect forwarding, discussed in the article link below).
One practical easy-to-understand example is the class template std::unique_ptr. Since a unique_ptr maintains exclusive ownership of its underlying raw pointer, unique_ptr's can't be copied. That would violate their invariant of exclusive ownership. So they do not have copy constructors. But they do have move constructors:
template<class T> class unique_ptr {
//...snip
unique_ptr(unique_ptr&& __u) noexcept; // move constructor
};
std::unique_ptr<int[] pt1{new int[10]};
std::unique_ptr<int[]> ptr2{ptr1};// compile error: no copy ctor.
// So we must first cast ptr1 to an rvalue
std::unique_ptr<int[]> ptr2{std::move(ptr1)};
std::unique_ptr<int[]> TakeOwnershipAndAlter(std::unique_ptr<int[]> param,\
int size)
{
for (auto i = 0; i < size; ++i) {
param[i] += 10;
}
return param; // implicitly calls unique_ptr(unique_ptr&&)
}
// Now use function
unique_ptr<int[]> ptr{new int[10]};
// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(\
static_cast<unique_ptr<int[]>&&>(ptr), 10);
cout << "output:\n";
for(auto i = 0; i< 10; ++i) {
cout << new_owner[i] << ", ";
}
output:
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
static_cast<unique_ptr<int[]>&&>(ptr) is usually done using std::move
// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(std::move(ptr),0);
An excellent article explaining all this and more (like how rvalues allow perfect forwarding and what that means) with lots of good examples is Thomas Becker's C++ Rvalue References Explained. This post relied heavily on his article.
A shorter introduction is A Brief Introduction to Rvalue References by Stroutrup, et. al

Is the lifetime of a reference extended?

I'd like to pass a reference into a function. This code does not work, as I'd expect:
struct A {
};
void foo(A& a) {
// do something with a
}
int main(int, char**) {
foo(A());
}
I get the compile error
invalid initialization of non-const reference of type A& from an rvalue of type A
But when I just add the method A& ref() to A like below and call it before passing it along, it seems I can use a. When debugging, the A object is destroyed after foo() is called:
struct A {
A& ref() {
return *this;
}
};
void foo(A& a) {
// do something with a
}
int main(int, char**) {
foo(A().ref());
}
Is this valid code according to the standard? Does calling ref() magically extend the lifetime of the object until foo() returns?
Your code is perfectly valid.
In this line
foo(A().ref());
The instance of a temporary A lives until the end of the statement (;).
That's why it's safe to pass A& returned from ref() to foo (as long as foo doesn't store it).
ref() by itself does not extend any lifetime, but it helps by returning an lvalue reference.
What happens in the case of foo(A()); ? Here the temporary is passed as an rvalue. And in C++ an rvalue does not bind to non-const lvalue references (even in C++11, an rvalue reference does not bind to non-const lvalue references).
From this Visual C++ blog article about rvalue references:
... 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 ...
A() creates a temporary object of type A. The object exists until the end of the full expression in which it is created. The problem in your original code is not the lifetime of this temporary; it's that the function takes its argument as a non-const reference, and you're not allowed to pass a temporary object as a non-const reference. The simplest change is for foo to take it's argument by const reference, if that's appropriate to what the function does:
void foo(const A&);
int main() {
foo(A());
}
There are several questions in this question. I'll attempt to address all of them:
First, you cannot pass a temporary (prvalue) of type A to a function taking A& because non-const lvalue references cannot bind to rvalues. That's a language restriction. If you want to be able to pass a temporary, you either need to take a parameter of type A&& or of type A const& - the latter since temporaries can bind to const lvalue references.
Is this valid code according to the standard? Does calling ref() magically extend the lifetime of the object until foo() returns?
There is no lifetime extension going on in your program at all. From [class.temp]:
There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array with
no corresponding initializer (8.6). The second context is when a copy constructor is called to copy an element
of an array while the entire array is copied (5.1.5, 12.8). [...] The third context is when a reference is bound to a temporary.
None of those contexts apply. We are never binding a reference to a temporary in this code. ref() binds *this to an A&, but *this is not a temporary, and then that resulting reference is simply passed into foo().
Consider this variant of your program:
#include <iostream>
struct A {
A& ref() { return *this; }
~A() { std::cout << "~A()\n"; }
};
int main() {
auto& foo = A().ref();
std::cout << "----\n";
}
which prints
~A()
----
illustrating that there is no lifetime extension.
If instead of binding the result of ref() to a reference we instead bound a member:
#include <iostream>
struct A {
A& ref() { return *this; }
int x;
~A() { std::cout << "~A()\n"; }
};
int main() {
auto&& foo = A().x;
std::cout << "----\n";
}
then we actually are binding a temporary to a reference and that third context applies - the lifetime of the complete object of the subobject to which the reference is bound is persisted for the lifetime of the reference. So this code prints:
----
~A()

What is meaning of returning by reference reference `&&` [duplicate]

I've been looking into some of the new features of C++11 and one I've noticed is the double ampersand in declaring variables, like T&& var.
For a start, what is this beast called? I wish Google would allow us to search for punctuation like this.
What exactly does it mean?
At first glance, it appears to be a double reference (like the C-style double pointers T** var), but I'm having a hard time thinking of a use case for that.
It declares an rvalue reference (standards proposal doc).
Here's an introduction to rvalue references.
Here's a fantastic in-depth look at rvalue references by one of Microsoft's standard library developers.
CAUTION: the linked article on MSDN ("Rvalue References: C++0x Features in VC10, Part 2") is a very clear introduction to Rvalue references, but makes statements about Rvalue references that were once true in the draft C++11 standard, but are not true for the final one! Specifically, it says at various points that rvalue references can bind to lvalues, which was once true, but was changed.(e.g. int x; int &&rrx = x; no longer compiles in GCC) – drewbarbs Jul 13 '14 at 16:12
The biggest difference between a C++03 reference (now called an lvalue reference in C++11) is that it can bind to an rvalue like a temporary without having to be const. Thus, this syntax is now legal:
T&& r = T();
rvalue references primarily provide for the following:
Move semantics. A move constructor and move assignment operator can now be defined that takes an rvalue reference instead of the usual const-lvalue reference. A move functions like a copy, except it is not obliged to keep the source unchanged; in fact, it usually modifies the source such that it no longer owns the moved resources. This is great for eliminating extraneous copies, especially in standard library implementations.
For example, a copy constructor might look like this:
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
If this constructor were passed a temporary, the copy would be unnecessary because we know the temporary will just be destroyed; why not make use of the resources the temporary already allocated? In C++03, there's no way to prevent the copy as we cannot determine whether we were passed a temporary. In C++11, we can overload a move constructor:
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
Notice the big difference here: the move constructor actually modifies its argument. This would effectively "move" the temporary into the object being constructed, thereby eliminating the unnecessary copy.
The move constructor would be used for temporaries and for non-const lvalue references that are explicitly converted to rvalue references using the std::move function (it just performs the conversion). The following code both invoke the move constructor for f1 and f2:
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
Perfect forwarding. rvalue references allow us to properly forward arguments for templated functions. Take for example this factory function:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
If we called factory<foo>(5), the argument will be deduced to be int&, which will not bind to a literal 5, even if foo's constructor takes an int. Well, we could instead use A1 const&, but what if foo takes the constructor argument by non-const reference? To make a truly generic factory function, we would have to overload factory on A1& and on A1 const&. That might be fine if factory takes 1 parameter type, but each additional parameter type would multiply the necessary overload set by 2. That's very quickly unmaintainable.
rvalue references fix this problem by allowing the standard library to define a std::forward function that can properly forward lvalue/rvalue references. For more information about how std::forward works, see this excellent answer.
This enables us to define the factory function like this:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
Now the argument's rvalue/lvalue-ness is preserved when passed to T's constructor. That means that if factory is called with an rvalue, T's constructor is called with an rvalue. If factory is called with an lvalue, T's constructor is called with an lvalue. The improved factory function works because of one special rule:
When the function parameter type is of
the form T&& where T is a template
parameter, and the function argument
is an lvalue of type A, the type A& is
used for template argument deduction.
Thus, we can use factory like so:
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
Important rvalue reference properties:
For overload resolution, lvalues prefer binding to lvalue references and rvalues prefer binding to rvalue references. Hence why temporaries prefer invoking a move constructor / move assignment operator over a copy constructor / assignment operator.
rvalue references will implicitly bind to rvalues and to temporaries that are the result of an implicit conversion. i.e. float f = 0f; int&& i = f; is well formed because float is implicitly convertible to int; the reference would be to a temporary that is the result of the conversion.
Named rvalue references are lvalues. Unnamed rvalue references are rvalues. This is important to understand why the std::move call is necessary in: foo&& r = foo(); foo f = std::move(r);
It denotes an rvalue reference. Rvalue references will only bind to temporary objects, unless explicitly generated otherwise. They are used to make objects much more efficient under certain circumstances, and to provide a facility known as perfect forwarding, which greatly simplifies template code.
In C++03, you can't distinguish between a copy of a non-mutable lvalue and an rvalue.
std::string s;
std::string another(s); // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(const std::string&);
In C++0x, this is not the case.
std::string s;
std::string another(s); // calls std::string(const std::string&);
std::string more(std::string(s)); // calls std::string(std::string&&);
Consider the implementation behind these constructors. In the first case, the string has to perform a copy to retain value semantics, which involves a new heap allocation. However, in the second case, we know in advance that the object which was passed in to our constructor is immediately due for destruction, and it doesn't have to remain untouched. We can effectively just swap the internal pointers and not perform any copying at all in this scenario, which is substantially more efficient. Move semantics benefit any class which has expensive or prohibited copying of internally referenced resources. Consider the case of std::unique_ptr- now that our class can distinguish between temporaries and non-temporaries, we can make the move semantics work correctly so that the unique_ptr cannot be copied but can be moved, which means that std::unique_ptr can be legally stored in Standard containers, sorted, etc, whereas C++03's std::auto_ptr cannot.
Now we consider the other use of rvalue references- perfect forwarding. Consider the question of binding a reference to a reference.
std::string s;
std::string& ref = s;
(std::string&)& anotherref = ref; // usually expressed via template
Can't recall what C++03 says about this, but in C++0x, the resultant type when dealing with rvalue references is critical. An rvalue reference to a type T, where T is a reference type, becomes a reference of type T.
(std::string&)&& ref // ref is std::string&
(const std::string&)&& ref // ref is const std::string&
(std::string&&)&& ref // ref is std::string&&
(const std::string&&)&& ref // ref is const std::string&&
Consider the simplest template function- min and max. In C++03 you have to overload for all four combinations of const and non-const manually. In C++0x it's just one overload. Combined with variadic templates, this enables perfect forwarding.
template<typename A, typename B> auto min(A&& aref, B&& bref) {
// for example, if you pass a const std::string& as first argument,
// then A becomes const std::string& and by extension, aref becomes
// const std::string&, completely maintaining it's type information.
if (std::forward<A>(aref) < std::forward<B>(bref))
return std::forward<A>(aref);
else
return std::forward<B>(bref);
}
I left off the return type deduction, because I can't recall how it's done offhand, but that min can accept any combination of lvalues, rvalues, const lvalues.
The term for T&& when used with type deduction (such as for perfect forwarding) is known colloquially as a forwarding reference. The term "universal reference" was coined by Scott Meyers in this article, but was later changed.
That is because it may be either r-value or l-value.
Examples are:
// template
template<class T> foo(T&& t) { ... }
// auto
auto&& t = ...;
// typedef
typedef ... T;
T&& t = ...;
// decltype
decltype(...)&& t = ...;
More discussion can be found in the answer for: Syntax for universal references
An rvalue reference is a type that behaves much like the ordinary reference X&, with several exceptions. The most important one is that when it comes to function overload resolution, lvalues prefer old-style lvalue references, whereas rvalues prefer the new rvalue references:
void foo(X& x); // lvalue reference overload
void foo(X&& x); // rvalue reference overload
X x;
X foobar();
foo(x); // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)
So what is an rvalue? Anything that is not an lvalue. An lvalue being
an expression that refers to a memory location and allows us to take the address of that memory location via the & operator.
It is almost easier to understand first what rvalues accomplish with an example:
#include <cstring>
class Sample {
int *ptr; // large block of memory
int size;
public:
Sample(int sz=0) : ptr{sz != 0 ? new int[sz] : nullptr}, size{sz}
{
if (ptr != nullptr) memset(ptr, 0, sz);
}
// copy constructor that takes lvalue
Sample(const Sample& s) : ptr{s.size != 0 ? new int[s.size] :\
nullptr}, size{s.size}
{
if (ptr != nullptr) memcpy(ptr, s.ptr, s.size);
std::cout << "copy constructor called on lvalue\n";
}
// move constructor that take rvalue
Sample(Sample&& s)
{ // steal s's resources
ptr = s.ptr;
size = s.size;
s.ptr = nullptr; // destructive write
s.size = 0;
cout << "Move constructor called on rvalue." << std::endl;
}
// normal copy assignment operator taking lvalue
Sample& operator=(const Sample& s)
{
if(this != &s) {
delete [] ptr; // free current pointer
size = s.size;
if (size != 0) {
ptr = new int[s.size];
memcpy(ptr, s.ptr, s.size);
} else
ptr = nullptr;
}
cout << "Copy Assignment called on lvalue." << std::endl;
return *this;
}
// overloaded move assignment operator taking rvalue
Sample& operator=(Sample&& lhs)
{
if(this != &s) {
delete [] ptr; //don't let ptr be orphaned
ptr = lhs.ptr; //but now "steal" lhs, don't clone it.
size = lhs.size;
lhs.ptr = nullptr; // lhs's new "stolen" state
lhs.size = 0;
}
cout << "Move Assignment called on rvalue" << std::endl;
return *this;
}
//...snip
};
The constructor and assignment operators have been overloaded with versions that take rvalue references. Rvalue references allow a function to branch at compile time (via overload resolution) on the condition "Am I being called on an lvalue or an rvalue?". This allowed us to create more efficient constructor and assignment operators above that move resources rather copy them.
The compiler automatically branches at compile time (depending on the whether it is being invoked for an lvalue or an rvalue) choosing whether the move constructor or move assignment operator should be called.
Summing up: rvalue references allow move semantics (and perfect forwarding, discussed in the article link below).
One practical easy-to-understand example is the class template std::unique_ptr. Since a unique_ptr maintains exclusive ownership of its underlying raw pointer, unique_ptr's can't be copied. That would violate their invariant of exclusive ownership. So they do not have copy constructors. But they do have move constructors:
template<class T> class unique_ptr {
//...snip
unique_ptr(unique_ptr&& __u) noexcept; // move constructor
};
std::unique_ptr<int[] pt1{new int[10]};
std::unique_ptr<int[]> ptr2{ptr1};// compile error: no copy ctor.
// So we must first cast ptr1 to an rvalue
std::unique_ptr<int[]> ptr2{std::move(ptr1)};
std::unique_ptr<int[]> TakeOwnershipAndAlter(std::unique_ptr<int[]> param,\
int size)
{
for (auto i = 0; i < size; ++i) {
param[i] += 10;
}
return param; // implicitly calls unique_ptr(unique_ptr&&)
}
// Now use function
unique_ptr<int[]> ptr{new int[10]};
// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(\
static_cast<unique_ptr<int[]>&&>(ptr), 10);
cout << "output:\n";
for(auto i = 0; i< 10; ++i) {
cout << new_owner[i] << ", ";
}
output:
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
static_cast<unique_ptr<int[]>&&>(ptr) is usually done using std::move
// first cast ptr from lvalue to rvalue
unique_ptr<int[]> new_owner = TakeOwnershipAndAlter(std::move(ptr),0);
An excellent article explaining all this and more (like how rvalues allow perfect forwarding and what that means) with lots of good examples is Thomas Becker's C++ Rvalue References Explained. This post relied heavily on his article.
A shorter introduction is A Brief Introduction to Rvalue References by Stroutrup, et. al