右值引用与移动:
C++11中引用了右值引用和移动语义,可以避免无谓的复制,提高了程序性能。
区分表达式的左右值属性:如果可对表达式用&符取址,则为左值,否则为右值。
在进入正题之前,首先得区分什么是左右值:
左值 lvalue 是有标识符、可以取地址的表达式,最常见的情况有:
**变量、函数或数据成员的名字
**返回左值引用的表达式,如 ++x、x = 1、cout << ' '
**字符串字面量如 "hello world"
纯右值 prvalue 是没有标识符、不可以取地址的表达式,一般也称之为“临时对象”。最常见的情况有:
**返回非引用类型的表达式,如 x++、x + 1、make_shared(42)
**除字符串字面量之外的字面量,如 42、true
C++11为我们提供了一种能引用右值的办法:
1. &&:
&&: 左右值都可以引用
& : 肯定是左值引用
右值引用就是对一个右值进行引用的类型。因为右值没有名字,所以我们只能通过引用的方式找到它。无论声明左值引用还是右值引用都必须立即进行初始化,因为引用类型本身并不拥有所把绑定对象的内存,只是该对象的一个别名。
特点如下:
1. 左值和右值是独立于它们的类型的,右值引用类型可能是左值也可能是右值。
2. auto&& 或函数参数类型自动推导的 T&& 是一个未定的引用类型,被称为 universal references,它可能是左值引用也可能是右值引用类型,取决于初始化的值类型。
3. 所有的右值引用叠加到右值引用上仍然是一个右值引用,其他引用折叠都为左值引用。当 T&& 为模板参数时,输入左值,它会变成左值引用,而输入右值时则变为具名的右值引用。
4. 编译器会将已命名的右值引用视为左值,而将未命名的右值引用视为右值。
特点理解起来不是很容易,先看一下右值引用:
#include <iostream>
using namespace std;
class A
{
public:
A() :m_ptr(new int(0)) {
cout << "constructor A" << endl;
}
~A(){
cout << "destructor A, m_ptr:" << m_ptr << endl;
delete m_ptr;
m_ptr = nullptr;
}
private:
int* m_ptr;
};
// 为了避免返回值优化(删除保持函数返回值的临时对象),此函数故意这样写???
A Get(bool flag)
{
A a;
A b;
cout << "ready return" << endl;
if (flag)
return a;
else
return b;
}
int main()
{
{