Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
In this article, we have explored the idea of T&& (double ampersand) in C++11. T&& was firstly introduced in the C++ 11 standard which declares an rvalue reference.
References
There two value references-
- lvalue reference
- rvalue reference
"L" stands for left in lvalue reference and "R" stands for right in rvalue reference.The thing to remember is that these are properties of expressions and not objects.
lvalue continue to exists beyond a expression while rvalue till an expression ends baecause l value is an mutable object declared on left and right hand side of an assignment while rvalue is temporary object asigned of an assignment.
In C++ 11, lvalue can bind the rvalue.Ex.
T&& a=T();
Code to unsderstand references-
#include <iostream>
int main() {
int a = 1; // a is an lvalue
int &ref1 = a; // ref1 is a lvalue reference
std::cout << "The address of ref1 is same as a: " << &a
<< ':' << &ref1 << '\n';
// int &&rref = a; // rvalue reference to type 'int' cannot bind to
// lvalue of type 'int'
int &&ref2 = 10;
std::cout << "Value of rref: " << ref2 << '\n';
// Can't take the address of an rvalue, but can take the address
// of an rvalue reference variable because it has a name :)
std::cout << "Address of ref2: " << &ref2 << '\n';
return 0;
}
Output-
The address of ref1 is same as x: 0x7ffc7ccd0790:0x7ffc7ccd0790
Value of ref2: 10
Address of ref2: 0x7ffc7ccd0794
By the above code we can get a little idea of what actually lvalue and rvalue reference. We can further enhace our knowledge rference of T&& by using it in a function.
Code
printR (const std::string& s) {
std::cout << "rvalue reference: " << s << '\n';
}
printR (std::string&& str) {
std::cout << "rvalue reference: " << s << '\n';
}
The first function will accept any argument whether it be lvalue or rvalue reference,while the second one will accept only rvalues except mutable rvalue refrences.
Now, we will call the function those functions to see what they return.
Code
std::string m = "OpenGenus";
printR(m); // calls function #1, taking an lvalue reference
printR("Joe"); // calls function #2, taking an rvalue reference
printR(std::string("Carl")) // function #2 too!
Rvalue references tell us whether the refrence variable is temporary object or permamnent.
Below is implemented the whole program mentioned above in parts-
Code
#include <iostream>
using namespace std;
string printR (const string& s) {
cout << "rvalue reference: " << s << '\n';
}
string printR (string&& s) {
cout << "rvalue reference: " << s << '\n';
}
int main() {
string a = "OpenGenus";
string s1=printR(a);
string s2=printR("Joe"); // calls function #2, taking an rvalue reference
string s3=printR(string("Carl")) ;// function #2 too!
cout<<s1;
cout<<s2;
cout<<s3;
return 0;
}
Output
rvalue reference: OpenGenus
rvalue reference: Joe
rvalue reference: Carl
Rvalue references provide the following-
- Move semantics-
Using the above code has its side effect but it doesnt really matter until we use a very large value is used which eventually distinguishes the rvalue and lvalue references.So,moving large objects costs us much more memory,why don't we use something that uses the memory used by the temporary rvalue.
To apply this we need to use move constructor and move assignment which takes rvalue reference and move functions like a copy which is good for eliminating copies standard library.
Ex.
f(f const& a)
{
this->length = a.length;
this->ptr = new int[a.length];
copy(a.ptr, a.ptr + a.length, this->ptr);
}
Now if we overload our constructor-
f(f&& a)
{
this->length = a.length;
this->ptr = a.ptr;
a.length = 0;
a.ptr = nullptr;
}
Now, the move constructor actually modifies its arguments ahich eleminates its copies and efficiently moves constructor.
2.Perfect forwarding-
Rvalue references allows us to forward arguments for template functions.
Template functions are those functions which adapt more than one type for increasing reusability.Ex.
template <typename T1, typename A1>
utr<T1> factory(A1& a1)
{
return unique_ptr<T1>(new T1(forward<A1>(a1)));
}
Important Properties of references-
By the above explanation we can understand the following -
- Lvalue is anything that has a name.Ex.int a = 1 ,
int &r = a.
2.Lvalue is an mutable object that has memory address.
3.Rvalue is a temporary object that is on right hand side of an assignment.
4.Lvakue can be placed on any side of assignment right or left both.
With this article at OpenGenus, you must have the complete idea of T&& (double ampersand) in C++11.