std::move
std::move是c++11引入的,用于将一个资源"移动"到另一个对象,而不是复制。但是通过std::move的源码可以发现,其底层实际并没有"转移"的动作,那是如何实现呢?
std::move的源码如下所示:
template <class _Ty>
_NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable
return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}
通过源码可以发现,std::move的底层实际只是进行了类型强制转换,将一个变量强制转换成了一个右值。
1.remove_reference_t<_Ty>:用于类型转换,用于移除_Ty的引用,如果_Ty是T&或者T&&,都会变成T类型
2._Arg是函数参数,并且是一个右值引用,因此参数可以是左值也可以是右值
3.return static_cast<remove_reference_t<_Ty>&&>(_Arg),首先移除了_Arg的引用,然后将_Arg强制转换成了remove_reference_t<_Ty>类型的右值引用。因此,无论_Arg是左值还是右值,都会被强制转换为右值。从而可以安全的调用移动构造函数或者移动复制运算符。
示例:
首先通过构造函数构造一个对象a,然后通过std::move函数将a强制转换成一个右值,然后可以通过移动构造函数进行赋值
class Base
{
public:
Base()
{
std::cout << "constructor" << std::endl;
}
Base(const Base&)
{
std::cout << "copy constructor" << std::endl;
}
Base(const Base&&)
{
std::cout << "move constructor" << std::endl;
}
};
int main()
{
Base a;//constructor
Base b = std::move(a);//move constructor
return 0;
}
std::forward
std::forward也是c++11引入的,用于原样(完美)转发
std::forward的源码如下所示:
template <class _Ty>
_NODISCARD constexpr _Ty&& forward(
remove_reference_t<_Ty>& _Arg) noexcept { // forward an lvalue as either an lvalue or an rvalue
return static_cast<_Ty&&>(_Arg);
}
1._Arg是函数参数,使用remove_reference_t<_Ty>移除了引用,然后通过&使其变成了一个左值引用
2.return static_cast<_Ty&&>(_Arg),这里进行了强制类型转换,通过static_cast将_Arg转换成了_Ty类型的右值引用。这个转换保持了_Arg的原始值类型(左值或者右值)。如果_Arg是一个左值,那么_Ty&&将变成_Ty&(左值引用),如果_Arg是一个右值,那么_Ty&&将变成_Ty&&(右值引用)。(这就是引用折叠规则)
区别
1.std::move是无条件的将一个值(无论是左值还是右值)强制转换为一个右值,以便可以调用右值引用的函数(如移动构造函数或移动赋值运算符)
2.std::forward用于完美转发,保持原参数的类型不变。即原始参数是左值引用,转发后还是左值引用,如果是右值引用,转发后就是右值引用。