欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

右值引用和对象移动

程序员文章站 2022-03-22 21:37:40
...

右值引用

概念

为了支持移动操作,C++11引入了一种新的引用类型-右值引用。就是必须绑定到右值的引用。我们通过&&而不是&来获得右值引用。右值引用只能绑定到一个将要销毁的对象。

由于右值引用只能绑定到临时对象,我们得知:

所引用的对象将要被销毁

该对象没有其他用户

这两个特性意味着:使用右值引用的代码可以自身*的接管所引用的对象的资源。

变量可以看作只有一个运算对象而没有运算符的表达式。

	int i = 23;
	int &&j = i;//错误:不能将一个右值引用绑定到一个左值上
	int &&k = i * 3;//正确,i*3是一个右值

标准库move函数

虽然不能将一个右值引用直接绑定到一个左值上,但可以通过调用一个名为move的新标准库函数来获得绑定到左值上的右值引用。

int i=6;
int &&l=std::move(i);

对象移动

提出

在很多情况下都会发生对象拷贝,比如利用reallocate重新分配内存的过程,在其中某些情况下,对象拷贝后就立即被销毁了。在这些情况下,移动而非拷贝对象会大幅度提升性能。

移动构造函数和移动赋值运算符

移动构造函数,参数是右值引用

StrVec::StrVec(StrVec &&s) noexcept                 //noexcept指名不抛出异常
:elements(s.elements), first_free(s.first_free),cap(s.cap)
{
            s.elements = s.first_free = s.cap = nullptr;  //销毁地动源后的对象
}

与拷贝构造函数不同,移动构造函数不分配任何新内存:它接管给定的StrVec中的内存。在接管内存后,它将给定对象中的指针都置为nullptr。

合成的移动操作

与处理拷贝构造函数和拷贝赋值运算符一样,编译器也会合成移动构造函数和移动赋值运算符。但是,合成移动构造的条件与合成拷贝操作的条件大不相同。

只有当一个类没有定义任何自己版本的拷贝控制成员(拷贝构造函数、拷贝赋值运算符、析构函数),且它的所有数据成员都能移动构造或移动赋值时,编译器才会为它合成移动构造函数或移动赋值运算符。

如果一个类定义了一个移动构造函数或一个移动赋值运算符,则该类的合成拷贝构造函数和拷贝赋值运算符被定义为删除的。

右值引用和成员函数

除了构造函数和赋值运算符之外,成员函数也可以同时提供拷贝版本和移动版本。例如:

void push_back(const X&);    //拷贝:绑定到任意类型的X
void push_back(X&&);    //移动:只能绑定到类型X的可修改的右值