为什么 std::move 采用前向引用
Why does std::move take a forward reference?
std::move
的实现基本上是这样的:
template<typename T>
typename std::remove_reference<T>::type&&
move(T&& t)
{
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
请注意,std::move
参数是通用引用(也称为转发引用,但我们在这里不转发)。也就是说,您可以同时std::move
左值和右值:
std::string a, b, c;
// ...
foo(std::move(a)); // fine, a is an lvalue
foo(std::move(b + c)); // nonsense, b + c is already an rvalue
但是,既然std::move
的全部意义在于投射到右值,为什么我们甚至被允许std::move
右值呢?如果std::move
只接受左值,不是更有意义吗?
template<typename T>
T&&
move(T& t)
{
return static_cast<T&&>(t);
}
然后,无意义的表达式std::move(b + c)
会导致编译时错误。
对于初学者来说,上述std::move
实现也更容易理解,因为代码完全符合它看起来的作用:它接受一个左值并返回一个右值。您不必了解通用引用、引用折叠和元函数。
那么,为什么std::move
被设计为同时采用左值和右值呢?
下面是一些简化到极致的例子:
#include <iostream>
#include <vector>
template<typename T>
T&& my_move(T& t)
{
return static_cast<T&&>(t);
}
int main()
{
std::vector<bool> v{true};
std::move(v[0]); // std::move on rvalue, OK
my_move(v[0]); // my_move on rvalue, OOPS
}
像上面这样的情况可能会出现在通用代码中,例如,当使用具有返回代理对象(右值)的专用化的容器时,您可能不知道客户端是否会使用该专用化,因此您需要无条件地支持移动语义。
它不疼。
你只是在建立一个保证,即代码会将结果视为右值。你当然可以这样写 std::move,这样在处理已经是右值的东西时它会出错,但有什么好处呢?
在通用代码中,你不一定知道你将使用什么类型,你会从一堆"如果类型是右值,什么都不做其他std::move"中提取出什么表现力的收益,当你可以简单地说"我保证我们可以把它看作是一个右值"时。
你自己说的,无非是演员阵容。如果参数已与预期类型匹配,则 *_cast 操作是否也应失败?
相关文章:
- 使用运算符 [] 引用 std::vector 上最后一个元素时出现问题<>
- 引用 std::any 或 not_yet_in_std::whatever 的惯用方式是什么?
- 引用 std::shared:ptr 以避免引用计数
- 将双指针作为参数传递给需要引用 std::vector <double>的函数
- 引用 std::cout 会导致段错误
- 无法通过引用 std::exception 来捕获从 std::exception 派生的类
- 为什么 std::runtime_error 的 c'tor 经常引用 std::string?
- 我可以在循环中引用 std::string 的一部分并将其放在外面吗?
- 引用 std::atomic <bool>的已删除函数错误
- 如何从对象中获取对元组尾部的引用 std::tuple<Head,Tail...>
- 当我编译引用 std::ostream 时,我有一个奇怪的错误弹出
- 错误 C2062:引用 std::map 时键入意外
- 设置 std::function 变量以引用 std::sin 函数
- 指针/引用 std::unordered_set 中的元素
- 迭代器引用 std::vector<std::unique_ptr<T>>
- C++:引用std::map中的计数值;std::multimap是更好的选择吗
- 未定义的引用std::对
- 引用std::basic_string特化string与自定义分配器作为std::string的常量对象,没有开销
- 使用c++,未定义引用std:: Makefile
- 常量引用std::vector