c++2.0新特性:右值引用和move语义

右值引用:解决不必要的copy。

左值和右值的区别:

1 .左值可以寻址,而右值不可以。
2 .左值可以被赋值,右值不可以被赋值,可以用来给左值赋值。
3 左值可变,右值不可变(仅对基础类型适用,用户自定义类型右值引用可以通过成员函数改变)。

例如:

class mystring
{
	char *data;
	int size;
}

x,y为mystring

mystring a(x);                                                             
mystring b(x + y);                                    //`相当于  string tmp=z+y;    string b(tmp);    tmp是个系统自动创建的匿名对象初始化完b后自动销毁。`
mystring c(some_function_returning_a_string());        //函数返回值为右值
//第一行括号内为左值,后两行为右值。
mystring(x);       //临时对象是一个右值(没有名字无法被赋值)

如果使用以下拷贝构造函数:

在这里插入图片描述

以上3行中,只有第一行的x深度拷贝是有必要的,因为我们可能会在后边用到x,x是一个左值(lvalues)。第二行和第三行的参数则是右值,因为表达式产生的string对象是匿名对象,之后没有办法再使用了

C++ 11引入了一种新的机制叫做“右值引用”,以便我们通过重载直接使用右值参数。我们所要做的就是写一个以右值引用为参数的构造函数:

转移构造函数:

string(string&& s) noexcept // string&& is an rvalue reference to a string , noexcept表示该函数不会产生错误
在这里插入图片描述
对于string b(x+y) 和 string c(some_function_returning_a_string())如果没定义转移构造函数将调用拷贝构造函数,如果定义了转移构造函数将调用转移构造函数(临时对象和函数返回值为右值)。对赋值操作符同理,也可以定义右值参数的赋值操作符=。string& operator=(string &&s) noexcept {…}

我们没有深度拷贝堆内存中的数据,而是仅仅复制了指针,并把源对象的指针置空。事实上,我们“偷取”了属于源对象的内存数据。由于源对象是一个右值,不会再被使用,因此客户并不会觉察到源对象被改变了。在这里,我们并没有真正的复制,所以我们把这个构造函数叫做“转移构造函数”(move constructor),他的工作就是把资源从一个对象转移到另一个对象,而不是复制他们。
在这里插入图片描述
当=右边是一个右值时,=左边的对象会偷取右边对象的资源,而不是重新分配内存。

有了右值引用,再来看看赋值操作符:

拷贝赋值:

在这里插入图片描述

转移赋值:

在这里插入图片描述
如果是a=b,这样就会调用复制构造函数来初始化s(因为b是左值),赋值操作符会与新创建的对象交换数据,深度拷贝。这就是copy and swap 惯用法的定义:构造一个副本,与副本交换数据,并让副本在作用域内自动销毁。这里也一样。
如果是a = x + y,这样就会调用转移构造函数来初始化s(因为x+y是右值),所以这里没有深度拷贝,只有高效的数据转移。相对于参数,s依然是一个独立的对象,但是他的构造函数是无用的(trivial),因此堆中的数据没有必要复制,而仅仅是转移。没有必要复制他,因为x+y是右值,再次,从右值指向的对象中转移是没有问题的。

总结一下:复制构造函数(对左值)执行的是深度拷贝,因为源对象本身必须不能被改变。而转移构造函数(对右值)却可以复制指针,把源对象的指针置空,这种形式下,这是安全的,因为用户不可能再使用这个对象了。

下面我们进一步讨论右值引用和move语义:

我们现在知道转移左值是十分危险的,但是转移右值却是很安全的。因为左值后面可能还会使用,右值不会。
右值引用是针对右值的新的引用类型,语法是 X&&。以前的老的引用类型 X& 现在被称作左值引用。
使用右值引用X&&作为参数的最有用的函数之一就是转移构造函数 X::X(X&& source),它的主要作用是把源对象的本地资源转移给当前对象。提高效率。

转移左值:std::move(lvalue)将左值转换为右值(可以理解为一种类型转换)

有时候,我们可能想转移左值,也就是说,有时候我们想让编译器把左值当作右值对待,以便能使用转移构造函数,即便这有点不安全。出于这个目的,C++ 11在标准库的头文件< utility >中提供了一个模板函数std::move。实际上,std::move仅仅是简单地将左值转换为右值,它本身并没有转移任何东西。它仅仅是让对象可以转移
注意:左值被转移了以后就不能在使用了。因为其内部资源已经转移给了别的对象

新版vector中insert方法使用了右值引用。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值