移动语义
仅仅转移资源的所有者,将资源的拥有者改为被赋值者,这就是所谓的移动语义,可以避免无谓的深拷贝,以提高性能。
C++中的所有容器都实现了移动语义,方便我们实现性能优化。
A& A::operator=(const A&& rhs) {
// 转移资源的控制权,无需复制
}
如何应用移动语义?
1.通过右值引用匹配临时值。
2.通过std::move方法将一个左值强制转换为右值引用。
std::move只是转移了资源的控制权,本质上是将左值变成右值引用,以用于移动语义,避免含有资源的的对象发生无谓的拷贝。
std::move对于拥有形如对内存、文件句柄等资源的成员的对象有效。如果是一些基本类型,比如int、char[10]数组等,实际上仍会发生拷贝,因为没有对应的移动构造函数,所以说std::move对于含有资源的对象更有意义。std::string有移动构造函数,但是经过测试,只有在string长度大于阈值(在堆上构建)才会调用移动构造函数。
完美转发
右值引用类型是独立于值的,一个右值引用参数作为函数的形参,在函数内部在转发该参数的时候它已经变成一个左值了,并不是它原来的类型了,比如:
void notPerfectForward(int&& i) {
printValue(i); // i是一个具名的对象,编译器会当做左值处理
}
因此我们需要一种方法能够按照参数原本的类型转发到另一个函数,这种转发被称为完美转发。
所谓的完美转发(Perfect Forwarding),是指在函数模板中,完全依照模板的参数的类型(即保持参数的左值、右值特征),将参
数传递给函数模板中调用的另一个函数。
template<typename T>
void perfectForward(T &&t) {
printValue(std::forward<T>(t));
}
完美转发也不一定只用于函数模板:
Data p;
Data && p1 = std::move(p);
func(std::forward<Data>(p1)); // OK
void func_1(Data && data)
{
func(std::forward<Data>(data));
}