C++11新标准 对象移动和右值引用

在看c++ primer的时候,了解到了一个c++11的新标准,故记录一下自己的见解。

std::move(对象移动)

需求

首先,这是C++为了避免copy的一种新做法。

  • 正如我们之前了解到的,程序运行过程中很多情况下会发生对象拷贝,但如果在某些特殊情况下,object被copy后就开始销毁,那么如果使用对象move就能大幅度提高性能。
  • 另一个原因则是,像IO类或者unique_ptr类是不允许共享资源的,因此这些类不可以被copy。由此引发的一个是,在旧标准里面,容器只能保存可以被拷贝的类。而新标准里,可以保存不被拷贝的类,只要该类能被移动即可。

含义

举个例子,通过copy constructor,容器vector能将内部指向数据的指针copy起来,原指针则使其为null,这样就避免了对数据内容的copy。

简单说明一下,copy constructor就是分配新的资源,而move constructor则是接管了原来的资源,获得使用了原来资源的权利。

用c++ primer的说法是“窃取”了资源

rvalue reference(右值引用)

需求

为了支持move操作,c++11新标准引进了一个新的引用类型——rvalue reference

含义

顾名思义,右值引用则是绑定到右值得引用,这其中就涉及到了一个非常有用的性质——右值引用只能绑定到一个将要销毁的对象。只有这样,我们才能将原对象资源move到新的对象当中去。

  • 我们把常规的引用叫做左值引用,通过&来取得;不能将其绑定到需要转换的表达式,字面常量和返回右值得表达式
  • 而通过&&则可以获得右值引用;同理,右值引用则有着相反的性质,不能将右值应用绑定到左值上;

举个例子:

1
2
3
4
5
6
7
8
9
int i = 42;
int &r = i; // lvalue reference
int &&rr = i; // rvalue reference (Error: i is a lvalue)
int &r2 = i*42; // lvalue reference (Error: i*42 is a rvalue)
const int &r3 = i*42; // reference to const (bind to a rvalue)
int &&rr2 = i*42; // rvalue reference
/*****************************************************/
int &&rr1 = 42 // rvalue reference (Error: 42 is a lvalue)
int &&rr2 = rr1 // rvalue reference (Error: rr1 is a lvalue)

注意一下,我们可以将一个const的左值引用或右值引用绑定到右值表达式上

总结一下,左值是持久的,右值是短暂的;因为只有将要被销毁的对象,我们才可以从绑定到右值引用的对象上获取其状态。

使用

这里先借用一下stackoverflow某位答主的话:

std::move() is a cast that produces an rvalue-reference to an object, to enable moving from it

为了我们可以将右值引用直接绑定到左值上,我们可以利用std::move这个标准库函数来获得绑定到左值上的右值引用。该函数定义在头文件utility中。

1
int &&rr2 = std::move(rr1); // ok
  • tips:由于move的名字冲突比其他标准库函数要频繁得多,因此最好加上限定语,不适用using。