std::move与std::forward
前言
本篇文章主要介绍std::move与std::forward的实现原理。
static_cast
在讲解两个函数之前,首先需要了解static_cast的作用。static_cast是C++中的一种 显式类型转换 运算符,用于在类型之间安全地进行编译期转换。其基本语法如下:
1 | |
其主要用法有:
(1)用于基本数据类型之间的转换,如把int转换为char,把int转换成enum,但这种转换的安全性需要开发者自己保证(这可以理解为保证数据的精度,即程序员能不能保证自己想要的程序安全),如在把int转换为char时,如果char没有足够的比特位来存放int的值(int>127或int<-127时),那么static_cast所做的只是简单的截断,即简单地把int的低8位复制到char的8位中,并直接抛弃高位
(2)把空指针转换成目标类型的空指针
(3)把任何类型的表达式类型转换成void类型
(4)用于类层次结构中父类和子类之间指针和引用的转换
1 | |
std::move
std::move()函数主要用于获取右值引用,其实现如下:
1 | |
_GLIBCXX_NODISCARD是一个宏,通常会展开为[[nodiscard]],表示调用者不应忽略该函数的返回值std::remove_reference<_Tp>::type&&是函数的返回类型std::remove_reference<_Tp>::type用于去掉_Tp上的引用(如果有)&&表示返回该类型的右值引用
move(_Tp&& __t) noexcept是函数名的参数部分_Tp&& __t是万能引用(forwarding reference),它可以匹配左值引用或右值引用- noexcept 表示这个函数不会抛出异常
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }将__t显式地转成右值引用。这是实现“右值强制转换”的关键
下面给出一个使用的示例,以说明std::move的原理:
1 | |
x是左值,对应的_Tp为int,返回值为int&&。a的类型为int&,去掉引用后转为int&&。
std::forward
std::forward是C++中用于完美转发(perfect forwarding)的核心工具,它的目的是在模板中把参数“原封不动”地传给另一个函数,保持它原本的左值或右值性质。
万能引用不是已经可以获得右值引用吗?为什么还需要std::forward呢?给出如下示例:
1 | |
我们希望传入左值实参和右值实参时,能够使用对应版本的process()函数进行处理,然而,C++中形参永远是左值,即使是如下函数,形参w依然是左值,因为w可以取地址。因此,和其他函数一样,param是一个左值,每次logAndProcess()调用内部函数process()时,都会调用它的左值重载版本。
1 | |
为了解决上述问题,就要用到std::forward,当param的实参是一个右值时,将param转换为右值:
1 | |
** 是否T&&就没有意义了?**
答案是否定的,T&&和std::forward是配合使用的,用于在模板函数中实现完美转发,自动适配左值/右值。而在非末班函数中,T&&用于明确只接收右值。