c++11引入了右值引用和移动语义(移动构造和移动赋值运算符),可以避免无谓的复制,提高程序性能。
1.右值引用
右值引用,记为T&&。左值是指表达式结束后依然存在的持久对象,右值是指表达式结束就不存在的临时对象。一个区分左值与右值的便捷方法是对表达式取地址,如果能则是左值,否则是右值。
右值包括:非引用返回的临时变量、运算表达式产生的临时变量、字面值、lambda表达式、std::move()返回值等....
2.移动构造
移动构造函数和移动赋值运算符以右值引用类型作为参数,移动语义通过浅拷贝的方式将资源从一个对象转移到另一个对象,从而减少不必要的临时对象的拷贝。
class A
{
public:
A():m_ptr(new char(0)) {}
A(const A& a):m_ptr(new char(*a.m_ptr)) {}
A(A &&a):m_ptr(a.m_ptr){a.m_ptr=nullptr;}
~A(){delete m_ptr;}
private:
char *m_ptr;
};
A GetA()
{
A a;
return a;
}
int main()
{
A a;
A b=a;//调用拷贝构造函数
A c=GetA();//调用移动构造函数
A d=std::move(a);//调用移动构造函数
return 0;
}
对于上述代码,由于a是左值 ,所以构造b时将调用拷贝构造函数。
而函数GetA返回值是临时对象,属于右值,因此构造c将调用移动构造函数,从而直接将GetA返回的临时对象的资源转交给c,假如没有移动构造而是调用拷贝构造函数的话,则需要拷贝GetA返回值,然后GetA返回值销毁。
所以何时调用拷贝构造何时调用移动构造是通过传入的参数来决定的,传入左值调用拷贝构造,传入右值调用移动构造。
3.std::move
std::move并不移动什么,它唯一的功能就是将一个左值强制转换为一个右值引用。真正的移动发生在移动构造函数和移动赋值运算符函数中,std::move的作用只是为了让调用构造函数的时候告诉编译器去选择移动构造函数.
A d=std::move(a);//调用移动构造函数,a对象的资源发生了移动
A &&d=std::move(a);//没有调用移动构造函数,只是将a转换为右值初始化d