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

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

右值引用

为了解决移动语义及完美转发问题,C++11标准引入了右值引用(rvalue reference)这一重要的新概念。右值引用采用T&&这一语法形式,比传统的引用T&(如今被称作左值引用 lvalue reference)多一个&。

如果把经由T&&这一语法形式所产生的引用类型都叫做右值引用,那么这种广义的右值引用又可分为以下三种类型:

无名右值引用 具名右值引用 转发型引用

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

转发型引用的引入主要是为了解决完美转发问题。 

无名右值引用

无名右值引用(unnamed rvalue reference)是指由右值引用相关操作所产生的引用类型。

无名右值引用主要通过返回右值引用的类型转换操作产生, 其语法形式如下:

static_cast<T&&>(t)

标准规定该语法形式将把表达式 t 转换为T类型的无名右值引用。

无名右值引用是右值,标准规定无名右值引用和传统的右值一样具有潜在的可移动性,即它所占有的资源可以被移动(窃取)。 

std::move()

由于无名右值引用是右值,借助于类型转换操作产生无名右值引用这一手段,左值表达式就可以被转换成右值表达式。为了便于利用这一重要的转换操作,标准库为我们提供了封装这一操作的函数,这就是std::move()。

假设左值表达式 t 的类型为T&,利用以下函数调用就可以把左值表达式 t 转换为T类型的无名右值引用(右值,类型为T&&)。
std::move(t)

具名右值引用

如果某个变量或参数被声明为T&&类型,并且T无需推导即可确定,那么这个变量或参数就是一个具名右值引用(named rvalue reference)。

具名右值引用是左值,因为具名右值引用有名字,和传统的左值引用一样可以用操作符&取地址。

与广义的右值引用相对应,狭义的右值引用仅限指具名右值引用。

传统的左值引用可以绑定左值,在某些情况下也可绑定右值。与此不同的是,右值引用只能绑定右值。

右值引用和左值引用统称为引用(reference),它们具有引用的共性,比如都必须在初始化时绑定值,都是左值等等。


struct X {}; 
X a; 
X&& b = static_cast<X&&>(a); 
X&& c = std::move(a); 
//static_cast<X&&>(a) 和 std::move(a) 是无名右值引用,是右值 
//b 和 c 是具名右值引用,是左值 
X& d = a; 
X& e = b; 
const X& f = c; 
const X& g = X(); 
X&& h = X(); 
//左值引用d和e只能绑定左值(包括传统左值:变量a以及新型左值:右值引用b) 
//const左值引用f和g可以绑定左值(右值引用c),也可以绑定右值(临时对象X()) 
//右值引用b,c和h只能绑定右值(包括新型右值:无名右值引用std::move(a)以及传统右值:临时对象X())