在C++11中,值参数(和其他值)在返回时享受隐式移动:
A func(A a) {
return a; // uses A::A(A&&) if it exists
}
至少在MSVC2010中,右值引用参数需要std::move
A func(A && a) {
return a; // uses A::A(A const&) even if A::A(A&&) exists
}
我可以想象,在函数内部,右值引用和值的行为类似,唯一的区别是,对于值,函数本身负责销毁,而对于右值引用,责任在外部。
在标准中区别对待它们的动机是什么?
发布于 2012-03-20 07:21:25
标准化委员会花费了大量的精力来创建措辞,以便只在两种情况下才会发生移动:
std::move
或类似的转换)。在函数结束时,value参数将毫无疑问地被销毁。因此,通过移动返回它显然是安全的;它不能在返回后被其他代码触及(除非你故意破坏东西,在这种情况下,你可能触发了未定义的行为)。因此,它可以从返回中移出。
&&
变量可以引用临时。但是它可以引用一个左值(一个命名变量)。因此,离开它显然是不安全的;原始变量可能潜伏在周围。而且由于您没有显式地要求从它移动(即:您没有在此函数中调用std::move
),所以不会发生任何移动。
只有当你返回一个&&
变量时,它才会被隐式地移出(比如:没有std::move
)。std::move<T>
返回一个T&&
。返回值调用move构造函数是合法,因为它是返回值。
现在,在不调用std::move
(或等效的强制转换)的情况下,使用左值调用A func(A &&a)
是非常困难的。因此,从技术上讲,隐式移动&&
类型的参数应该是可以的。但是标准委员会希望移动对于&&
类型是显式的,只是为了确保移动不会隐式地发生在此函数的范围内。也就是说,它不能使用关于&&
来自何处的函数外部知识。
一般来说,你应该只在两种情况下通过&&
获取参数:要么你正在编写一个移动构造函数(或者移动赋值操作符,但即使是这样也可以通过值来完成),或者你正在编写一个转发函数。可能还有其他几种情况,但除非您有特殊的想法,否则不应将&&
应用于某个类型。如果A
是可移动类型,则只需按值获取。
发布于 2012-03-20 07:24:57
在第一种情况下,编译器知道a
正在消失,没有任何东西能够附着在它上面:显然,这个对象可以被移走,如果不是这样,它将被销毁。在第二种情况下,rvalue引用表示允许从对象中移动,并且调用者不希望对象停留在原地。然而,这是函数的选择,它是否利用这个权限,可能有一些原因,函数有时想要离开参数,有时不想。如果编译器可以自由地移出这个对象,那么就没有办法阻止编译器这样做。然而,使用std::move(a)
已经有了一种方法来指示它希望从对象中移动。
标准中的一般规则是编译器只会隐式地移动已知会消失的对象。当一个右值引用进来时,编译器并不真的知道对象将要离开:如果它被显式地std::move()
ed,它实际上会留在原处。
发布于 2019-10-19 09:04:07
这是由P0527和P1825为C++20修复的。将函数参数绑定到右值引用的唯一方法是让源成为临时值,或者让调用者显式地将非临时值转换为右值(例如,使用std::move
)。因此,这种“强制优化”被认为是安全的。
https://stackoverflow.com/questions/9779079
复制相似问题