C++右值引用的用法(附带实例)
C++ 中,右值引用是一种特殊的引用类型,用于支持移动语义和完美转发。
右值引用能够识别临时对象(也就是右值)。具体来讲,如果一个对象在其生命周期的最后一步,则可以安全地将其资源“移动”到另一个对象,而不是像传统的复制构造函数那样执行深复制。由于移动语义没有内存复制操作,所以移动语义可以显著地提高代码性能。
使用 && 声明一个右值引用。例如:
std::move 是一个函数,它可以将传递给它的对象转换为右值,这样就可以将其资源移动到另一个对象。在 GCC 13.2.0 中的 STL 关于 std::move 的主要部分如下:
移动构造函数和移动赋值这些特殊的成员函数可以将资源从源对象移动到目标对象,而不是像复制构造函数那样深复制资源。移动构造函数通常接受一个右值引用参数,例如 MyType(MyType&&other)。
std::forward<>() 模板函数可以将参数以完全传递的形式(完全按照原样,即保持原有类型,可以是左值或右值)转发给其他函数。这个功能在模板编程中特别有用,例如在实现泛型编程中的“完美转发”时。
在 GCC 13.2.0 STL 中,关于 std::forward<>() 的代码主要如下:
右值引用能够识别临时对象(也就是右值)。具体来讲,如果一个对象在其生命周期的最后一步,则可以安全地将其资源“移动”到另一个对象,而不是像传统的复制构造函数那样执行深复制。由于移动语义没有内存复制操作,所以移动语义可以显著地提高代码性能。
使用 && 声明一个右值引用。例如:
int a=10; int&&rv=std::move(a);这里 std::move(a) 将 a 转换为右值,所以 rv 是 a 的一个右值引用。
std::move 是一个函数,它可以将传递给它的对象转换为右值,这样就可以将其资源移动到另一个对象。在 GCC 13.2.0 中的 STL 关于 std::move 的主要部分如下:
template<typename_Tp> constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&&__t)noexcept { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }实际上使用 static_cast 是进行强制类型转换的操作,而这个操作函数是用 constexpr 修饰的,是一个在编译期就被执行的函数。std::remove_reference<> 元函数用来移除类型的引用符号。
移动构造函数和移动赋值这些特殊的成员函数可以将资源从源对象移动到目标对象,而不是像复制构造函数那样深复制资源。移动构造函数通常接受一个右值引用参数,例如 MyType(MyType&&other)。
std::forward<>() 模板函数可以将参数以完全传递的形式(完全按照原样,即保持原有类型,可以是左值或右值)转发给其他函数。这个功能在模板编程中特别有用,例如在实现泛型编程中的“完美转发”时。
在 GCC 13.2.0 STL 中,关于 std::forward<>() 的代码主要如下:
template<typename_Tp> constexpr_Tp&& forward(typename std::remove_reference<_Tp>::type&__t) { return static_cast<_Tp&&>(__t); } template<typename_Tp> constexpr_Tp&& forward(typename std::remove_reference<_Tp>::type&&__t) { static_assert(!std::is_lvalue_reference<_Tp>::value, "std::forward must not be used to convert an rvalue to an lvalue"); return static_cast<_Tp&&>(__t); }可以从代码中看出,std::forword<>() 主要由两个函数组成,一个用于右值引用,另一个用于左值引用,内部实际使用了类型强制转换的方式实现:
- 当参数右值引用时使用第 2 个函数,需要在右值引用上增加 &&,通过引用折叠后仍然获得一个右值应用;
- 当数据类型为一个左值引用时调用第 1 个函数,通过引用折叠规则仍然获得一个左值引用。