为什么 C++ 默认不移动构造右值引用?
Why doesn't C++ move construct rvalue references by default?
假设我有以下功能
void doWork(Widget && param) // param is an LVALUE of RRef type
{
Widget store = std::move(param);
}
为什么我需要用 std::move()
将 param
转换回右值? param
的类型是右值,因为它在函数签名中被声明为右值引用,难道不应该很明显吗?仅仅根据这个原则,这里不应该自动调用移动构造函数吗?
为什么默认情况下不发生这种情况?
你的设计:
void doWork(Widget && param)
{
Widget store1 = param; // automatically move param
Widget store2 = param; // boom
Widget store_last = param; // boom
}
当前设计:
void doWork(Widget && param)
{
Widget store1 = param; // ok, copy
Widget store2 = param; // ok, copy
Widget store_last = std::move(param); // ok, param is moved at its last use
}
所以这里的寓意是,即使您有一个右值引用,您也有一个名称,这意味着您可以多次使用它。因此,您不能自动移动它,因为您以后可能需要它。
现在假设您想重新设计语言,以便最后一次使用自动被视为右值。
这在上面的例子中很容易做到:
void doWork(Widget && param)
{
Widget store1 = param; // `param` treated as lvalue here, copy
Widget store2 = param; // `param` treated as lvalue here, copy
Widget store_last = param; // `param` treated as rvalue here, move
}
让我们忽略 param
处理方式的不一致(这本身就是一个问题)。
现在想想param
最后的用途是什么:
void doWork(Widget && param)
{
Widget store2 = param; // this can be last use or not
while (some_condition())
{
Widget store1 = param; // this can be both last use and not
}
}
语言根本不能这样设计。
假设我有以下功能
void doWork(Widget && param) // param is an LVALUE of RRef type
{
Widget store = std::move(param);
}
为什么我需要用 std::move()
将 param
转换回右值? param
的类型是右值,因为它在函数签名中被声明为右值引用,难道不应该很明显吗?仅仅根据这个原则,这里不应该自动调用移动构造函数吗?
为什么默认情况下不发生这种情况?
你的设计:
void doWork(Widget && param)
{
Widget store1 = param; // automatically move param
Widget store2 = param; // boom
Widget store_last = param; // boom
}
当前设计:
void doWork(Widget && param)
{
Widget store1 = param; // ok, copy
Widget store2 = param; // ok, copy
Widget store_last = std::move(param); // ok, param is moved at its last use
}
所以这里的寓意是,即使您有一个右值引用,您也有一个名称,这意味着您可以多次使用它。因此,您不能自动移动它,因为您以后可能需要它。
现在假设您想重新设计语言,以便最后一次使用自动被视为右值。
这在上面的例子中很容易做到:
void doWork(Widget && param)
{
Widget store1 = param; // `param` treated as lvalue here, copy
Widget store2 = param; // `param` treated as lvalue here, copy
Widget store_last = param; // `param` treated as rvalue here, move
}
让我们忽略 param
处理方式的不一致(这本身就是一个问题)。
现在想想param
最后的用途是什么:
void doWork(Widget && param)
{
Widget store2 = param; // this can be last use or not
while (some_condition())
{
Widget store1 = param; // this can be both last use and not
}
}
语言根本不能这样设计。