值类别

  1. 左值:通常来讲是可以放在赋值运算符左边的表达式,左值具有持久性,拥有确定的内存地址,可以使用取地址符获取;
  2. 右值:通常来说是放在赋值运算符右边的右操作数,它是一个临时值,无法取地址操作。

右值引用

C++11 中引入了右值引用语义(&&),允许开发者对右值进行引用,从来实现移动语义和完美转发。

移动语义

std::move 是 C++11 引入的标准库函数,将一个左值强制转换为右值,从而实现移动语义。通过std::move可以不进行复制实现将一个对象转移到另一个对象,提高了性能。
但是std::move不移动任何东西,只是将传入的左值参数强制转化为右值引用

1
2
3
4
5
6
namespace std {
template<typename T>
constexpr remove_reference_t<T>&& move(T&& arg) noexcept {
return static_cast<remove_reference_t<T>&&>(arg);
}
}

这里使用了模版元编程中的remove_reference_t来去除T的引用,然后通过static_cast将其转换为右值引用。

完美转发

std::forward由 C++11 引用,用于实现完美转发。完美转发是指函数模板在将参数传递给其他函数时,保持原参数的值类型不变,并且不发生多余的拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
namespace std {
template<typename T>
constexpr T&& forward(remove_reference_t<T>& arg) noexcept {
return static_cast<T&&>(arg);
}

template<typename T>
constexpr T&& forward(remove_reference_t<T>&& arg) noexcept {
static_assert(!is_lvalue_reference_v<T>, "Can't forward an rvalue as an lvalue.");
return static_cast<T&&>(arg);
}
}