在C 11中,值参数(和其他值)在返回时享受隐式移动:
A func(A a) {
return a; // uses A::A(A&&) if it exists
}
至少在MSVC 2010中,右值参考参数需要 std::move
:
A func(A && a) {
return a; // uses A::A(A const&) even if A::A(A&&) exists
}
我认为内部函数,右值引用和值的行为类似,唯一的区别是在值的情况下,函数本身负责销毁,而对于右值引用,责任在外面 .
在标准中对待它们的动机是什么?
2 回答
标准化委员会在创建措辞方面付出了巨大的努力,因此只有在两种情况下才会发生变化:
这样做显然是安全的 .
当用户明确询问时(通过
std::move
或类似的演员) .毫无疑问,值参数将在函数末尾被销毁 . 因此,通过移动返回它显然是安全的;返回后它不能被其他代码触及(除非你故意试图破坏事物,在这种情况下你可能会触发未定义的行为) . 因此,它可以从返回中移动 .
&&
变量可能指的是临时变量 . 但它可能指的是左值(一个命名变量) . 因此,离开它是不明显的安全;原始变量可能潜伏着 . 因为你没有明确要求从它移动(即:你没有在这个函数中调用std::move
),所以不能进行任何移动 .只有当你返回时,
&&
变量才会被隐式移动(即:没有std::move
) .std::move<T>
返回T&&
. 返回值调用move构造函数是合法的,因为它是返回值 .现在很难用左值调用
A func(A &&a)
而不调用std::move
(或等效的强制转换) . 从技术上讲,&&
类型的参数可以隐式移动 . 但是,标准委员会希望采取措施明确&&
类型,只是为了确保运动没有使用关于&&
来自何处的功能外知识 .通常,在两种情况下,您应该仅通过
&&
获取参数:要么're writing a move constructor (or move assignment operator, but even that can be done by value), or you'重新编写转发函数 . 可能还有其他一些情况,但你不应该把&&
带到一个类型,除非你有一些特别的想法 . 如果A
是可移动类型,则只需按值取值即可 .在你的第一种情况下,编译器知道
a
正在消失,没有任何东西可以依赖它:显然,这个对象可以被移动,如果不是,它将被销毁 . 在第二种情况下,rvalue引用表明允许从对象移动并且调用者不选择是否利用此权限,并且可能存在函数有时想要从参数移出的原因 . 有时它不想 . 如果编译器可以自由移动此对象,则无法阻止编译器这样做 . 但是,使用std::move(a)
已经有一种方法可以指示需要从对象移动 .标准中的一般规则是编译器只会隐式移动已知会消失的对象 . 当一个rvalue引用进来时,编译器并不真正知道该对象即将离开:如果它明确地是
std::move()
ed它实际上保持不变 .