Rvalue references are a feature of C++ that was added with the C++11 standard. The syntax of an rvalue reference is to add && after a type.

In C++, there are rvalues and lvalues. An lvalue is an expression whose address can be taken,a locator value--essentially, an lvalue provides a (semi)permanent piece of memory. rvalues are not lvalues. An expression is an rvalue if it results in a temporary object.

Every C++ expression is either an lvalue or an rvalue. An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.

an "rvalue reference", that will let you bind a mutable reference to an rvalue, but not an lvalue. In other words, rvalue references are perfect for detecting if a value is temporary object or not. Rvalue references use the && syntax instead of just &, and can be const and non-const, just like lvalue references, although you'll rarely see a const rvalue reference.

Rvalue references solve at least two problems: Implementing move semantics; Perfect forwarding.

The original definition of lvalues and rvalues from the earliest days of C is as follows: An lvalue is an expression e that may appear on the left or on the right hand side of an assignment, whereas an rvalue is an expression that can only appear on the right hand side of an assignment.

If X is any type, then X&& is called an rvalue reference to X. For better distinction, the ordinary reference X& is now also called an lvalue reference.

rvalue references enable us to distinguish an lvalue from an rvalue.

In C++11,however, the rvalue reference lets us bind a mutable reference to an rvalue,but not an lvalue. In other words, rvalue references are perfect for detecting whether a value is a temporary object or not.

Important rvalue reference properties:

(1)、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.

(2)、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.

(3)、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).

Rvalue references enable you to distinguish an lvalue from an rvalue. Lvalue references and rvalue references are syntactically and semantically similar,but they follow somewhat different rules.

右值引用是C++11中最重要的新特性之一,它解决了C++中大量的历史遗留问题,使C++标准库的实现在多种场景下消除了不必要的额外开销(如std::vector, std::string),也使得另外一些标准库(如std::unique_ptr, std::function)成为可能。即使你并不直接使用右值引用,也可以通过标准库,间接从这一新特性中受益。

右值引用的意义通常解释为两大作用:移动语义和完美转发。

右值引用可以使我们区分表达式的左值和右值。

右值引用它实现了移动语义(Move Sementics)和完美转发(Perfect Forwarding)。它的主要目的有两个方面:(1)、消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率;(2)、能够更简洁明确地定义泛型函数。

右值引用主要就是解决一个拷贝效率低下的问题,因为针对于右值,或者打算更改的左值,我们可以采用类似与auto_ptr的move(移动)操作,大大的提高性能(move semantics)。另外,C++的模板推断机制为参数T&&做了一个例外规则,让左值和右值的识别和转向(forward)非常简单,帮助我们写出高效并且简捷的泛型代码(perfect forwarding)。

左值的声明符号为”&”, 为了和左值区分,右值的声明符号为”&&”。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "rvalue_references.hpp"
#include <iostream>
#include <string>
#include <utility>

//////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/language/reference
void double_string(std::string& s)
{
	s += s; // 's' is the same object as main()'s 'str'
}

char& char_number(std::string& s, std::size_t n)
{
	return s.at(n); // string::at() returns a reference to char
}

int test_lvalue_references1()
{
	// 1. Lvalue references can be used to alias an existing object (optionally with different cv-qualification):
	std::string s = "Ex";
	std::string& r1 = s;
	const std::string& r2 = s;

	r1 += "ample";           // modifies s
	//  r2 += "!";               // error: cannot modify through reference to const
	std::cout << r2 << '\n'; // prints s, which now holds "Example"

	// 2. They can also be used to implement pass-by-reference semantics in function calls:
	std::string str = "Test";
	double_string(str);
	std::cout << str << '\n';

	// 3. When a function's return type is lvalue reference, the function call expression becomes an lvalue expression
	std::string str_ = "Test";
	char_number(str_, 1) = 'a'; // the function call is lvalue, can be assigned to
	std::cout << str_ << '\n';

	return 0;
}

//////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/language/reference
static void f(int& x)
{
	std::cout << "lvalue reference overload f(" << x << ")\n";
}

static void f(const int& x)
{
	std::cout << "lvalue reference to const overload f(" << x << ")\n";
}

static void f(int&& x)
{
	std::cout << "rvalue reference overload f(" << x << ")\n";
}

int test_rvalue_references1()
{
	// 1. 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):
	std::string s1 = "Test";
	//  std::string&& r1 = s1;           // error: can't bind to lvalue

	const std::string& r2 = s1 + s1; // okay: lvalue reference to const extends lifetime
	//  r2 += "Test";                    // error: can't modify through reference to const

	std::string&& r3 = s1 + s1;      // okay: rvalue reference extends lifetime
	r3 += "Test";                    // okay: can modify through reference to non-const
	std::cout << r3 << '\n';

	// 2. More importantly, 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:
	int i = 1;
	const int ci = 2;
	f(i);  // calls f(int&)
	f(ci); // calls f(const int&)
	f(3);  // calls f(int&&)
	// would call f(const int&) if f(int&&) overload wasn't provided
	f(std::move(i)); // calls f(int&&)

	// This allows move constructors, move assignment operators, and other move-aware functions
	// (e.g. vector::push_back() to be automatically selected when suitable.

	return 0;
}

/////////////////////////////////////////////////////
// reference: http://www.bogotobogo.com/cplusplus/C11/5_C11_Move_Semantics_Rvalue_Reference.php
static void printReference(int& value)
{
	std::cout << "lvalue: value = " << value << std::endl;
}

static void printReference(int&& value)
{
	std::cout << "rvalue: value = " << value << std::endl;
}

static int getValue()
{
	int temp_ii = 99;
	return temp_ii;
}

int test_rvalue_references2()
{
	int ii = 11;
	printReference(ii);
	printReference(getValue());  //  printReference(99);
	return 0;
}

////////////////////////////////////////////////////////////
// references: https://msdn.microsoft.com/en-us/library/dd293668.aspx
template<typename T> struct S;

// The following structures specialize S by
// lvalue reference (T&), const lvalue reference (const T&),
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of
// the structure and its parameter.
template<typename T> struct S<T&> {
	static void print(T& t)
	{
		std::cout << "print<T&>: " << t << std::endl;
	}
};

template<typename T> struct S<const T&> {
	static void print(const T& t)
	{
		std::cout << "print<const T&>: " << t << std::endl;
	}
};

template<typename T> struct S<T&&> {
	static void print(T&& t)
	{
		std::cout << "print<T&&>: " << t << std::endl;
	}
};

template<typename T> struct S<const T&&> {
	static void print(const T&& t)
	{
		std::cout << "print<const T&&>: " << t << std::endl;
	}
};

// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t)
{
	S<T&&>::print(std::forward<T>(t));
}

// This function returns the constant string "fourth".
const std::string fourth() { return std::string("fourth"); }

int test_rvalue_references3()
{
	// The following call resolves to:
	// print_type_and_value<string&>(string& && t)
	// Which collapses to:
	// print_type_and_value<string&>(string& t)
	std::string s1("first");
	print_type_and_value(s1);

	// The following call resolves to:
	// print_type_and_value<const string&>(const string& && t)
	// Which collapses to:
	// print_type_and_value<const string&>(const string& t)
	const std::string s2("second");
	print_type_and_value(s2);

	// The following call resolves to:
	// print_type_and_value<string&&>(string&& t)
	print_type_and_value(std::string("third"));

	// The following call resolves to:
	// print_type_and_value<const string&&>(const string&& t)
	print_type_and_value(fourth());

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

C++11中rvalue references的使用的更多相关文章

  1. [转载] C++11中的右值引用

    C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...

  2. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述

    本文系对「C++ Rvalue References Explained」 该文的翻译,原文作者:Thomas Becker. 该文较详细的解释了C++11右值引用的作用和出现的意义,也同时被Scot ...

  3. C++ 11 中的右值引用

    C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream>    #include &l ...

  4. c++11 中的 move 与 forward

    [update: 关于左值右值的另一点总结,请参看这篇] 一. move 关于 lvaue 和 rvalue,在 c++11 以前存在一个有趣的现象:T&  指向 lvalue (左传引用), ...

  5. C++11中的右值引用

    原文出处:http://kuring.me/post/cpp11_right_reference May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移 ...

  6. 二十分钟弄懂C++11 的 rvalue reference (C++ 性能剖析 (5))

    C++ 11加了许多新的功能.其中对C++性能和我们设计class的constructor或assignment可能产生重大影响的非rvalue reference莫属!我看了不少资料,能说清它的不多 ...

  7. C++11 中值得关注的几大变化(网摘)

    C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...

  8. C++11 中值得关注的几大变化(详解)

    源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里. ...

  9. C++11中std::forward的使用 (转)

    std::forward argument: Returns an rvalue reference to arg if arg is not an lvalue reference; If arg ...

随机推荐

  1. Locust性能测试3 no-web运行

    Locust也支持no-web的方式运行,直接通过控制台设置并发用户数.每秒启动用户数.持续压测时间. locust -f 脚本路径 -c 用户数 -r 每秒启动用户数 --run-time 持续压测 ...

  2. 函子(Monad)新解:函子定义了一个类型(泛型)和建立在这个类型上的一组运算符

    这组运算符和代数中的运算加减乘除运算符一样,符合一定的定律:结合律.(交换律)等: 函数式编程的核心(底层支持)就是这些类型和运算符的定义. 函子就是定义这些类型和运算符的(). 运算符通常为单目运算 ...

  3. ShellSort uva

    ShellSort He made each turtle stand on another one's back And he piled them all up in a nine-turtle ...

  4. DateTime小综合

    实现效果: 关键知识: 1>DateTime类的ToString()方法: 2>DateTime类的IsLeapYear(); 3>DateTime类的DaysInMomth(); ...

  5. 【luogu P2169 正则表达式】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2169 tarjan缩点 + SPFA 缩完点之后加边注意别写错. 也可以不用建两个图,可以在一张图上判断是否 ...

  6. JavaEE权限管理系统的搭建(七)--------管理用户的增删改

    本小结讲解管理用户的增删改查实现, 首先是添加用户,如下图所示,可以看到添加用户的同时也要给用户分配角色,至少给用户分配一个或者是多个角色 页面js部分: $.ajax({ //几个参数需要注意一下 ...

  7. 下载YouTube视频的网站和工具

    1.界面友好,可选择的清晰度较多(我个人用这个比较多) http://en.savefrom.net/ 2.几乎可以解析到所有的清晰度 http://www.clipconverter.cc 3.可选 ...

  8. golang-Tag

    Tag 理解 Golang中可以对struct定义Tag 例如: type TestTag struct{ UserName string `json:"name"` Age In ...

  9. Java实现非递归归并排序

    public class nonRecursiveMergeSort { public static void main(String[] args) { int[] list = {8,4,3,6, ...

  10. c#数据库连接池Hikari重构升级

    Hikari是我自定义的数据库连接池,前面已经提供了地址.因为c#的连接池按照规范的ADO.NET里面实现定义的.由数据库官方提供,但是实现方式就不知道了,反正没有看出来,估计一般是连接类实现的,但是 ...