C++11右值引用和转发型引用教程详解

2020-01-06 18:30:57丽君

左右值重载策略

有时我们需要在函数中区分参数的左右值属性,根据参数左右值属性的不同做出不同的处理。适当地采用左右值重载策略,借助于左右值引用参数不同的绑定特性,我们可以利用函数重载来做到这一点。常见的左右值重载策略如下:


struct X {}; 
//左值版本 
void f(const X& param1){/*处理左值参数param1*/} 
//右值版本 
void f(X&& param2){/*处理右值参数param2*/} 
X a; 
f(a);      //调用左值版本 
f(X());     //调用右值版本 
f(std::move(a)); //调用右值版本 

即在函数重载中分别重载const左值引用和右值引用。

重载const左值引用的为左值版本,这是因为const左值引用参数能绑定左值,而右值引用参数不能绑定左值。

重载右值引用的为右值版本,这是因为虽然const左值引用参数和右值引用参数都能绑定右值,但标准规定右值引用参数的绑定优先度要高于const左值引用参数。

移动构造器和移动赋值运算符

在类的构造器和赋值运算符中运用上述左右值重载策略,就会产生两个新的特殊成员函数:移动构造器(move constructor)和移动赋值运算符(move assignment operator)。


struct X 
{ 
  X();             //缺省构造器 
  X(const X& that);      //拷贝构造器 
  X(X&& that);         //移动构造器 
  X& operator=(const X& that); //拷贝赋值运算符 
  X& operator=(X&& that);   //移动赋值运算符 
}; 
X a;               //调用缺省构造器 
X b = a;             //调用拷贝构造器 
X c = std::move(b);       //调用移动构造器 
b = a;              //调用拷贝赋值运算符 
c = std::move(b);        //调用移动赋值运算符 

移动语义

无名右值引用和具名右值引用的引入主要是为了解决移动语义问题。

移动语义问题是指在某些特定情况下(比如用右值来赋值或构造对象时)如何采用廉价的移动语义替换昂贵的拷贝语义的问题。

移动语义(move semantics)是指某个对象接管另一个对象所拥有的外部资源的所有权。移动语义需要通过移动(窃取)其他

对象所拥有的资源来完成。移动语义的具体实现(即一次that对象到this对象的移动(move))通常包含以下若干步骤:

如果this对象自身也拥有资源,释放该资源 将this对象的指针或句柄指向that对象所拥有的资源 将that对象原本指向该资源的指针或句柄设为空值  

上述步骤可简单概括为①释放this(this非空时)②移动that

移动语义通常在移动构造器和移动赋值运算符中得以具体实现。两者的区别在于移动构造对象时this对象为空因而①释放this无须进行。