首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么C++11对value参数有隐式移动,但对rvalue参数没有?

为什么C++11对value参数有隐式移动,但对rvalue参数没有?
EN

Stack Overflow用户
提问于 2012-03-20 06:49:03
回答 3查看 4.8K关注 0票数 23

在C++11中,值参数(和其他值)在返回时享受隐式移动:

代码语言:javascript
运行
复制
A func(A a) {
    return a; // uses A::A(A&&) if it exists
}

至少在MSVC2010中,右值引用参数需要std::move

代码语言:javascript
运行
复制
A func(A && a) {
    return a; // uses A::A(A const&) even if A::A(A&&) exists
}

我可以想象,在函数内部,右值引用和值的行为类似,唯一的区别是,对于值,函数本身负责销毁,而对于右值引用,责任在外部。

在标准中区别对待它们的动机是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-20 07:21:25

标准化委员会花费了大量的精力来创建措辞,以便只在两种情况下才会发生移动:

  1. 当这样做显然是安全的时。
  2. 当用户明确要求时(通过std::move或类似的转换)。

在函数结束时,value参数将毫无疑问地被销毁。因此,通过移动返回它显然是安全的;它不能在返回后被其他代码触及(除非你故意破坏东西,在这种情况下,你可能触发了未定义的行为)。因此,它可以从返回中移出。

&&变量可以引用临时。但是它可以引用一个左值(一个命名变量)。因此,离开它显然是不安全的;原始变量可能潜伏在周围。而且由于您没有显式地要求从它移动(即:您没有在此函数中调用std::move ),所以不会发生任何移动。

只有当你返回一个&&变量时,它才会被隐式地移出(比如:没有std::move)。std::move<T>返回一个T&&。返回值调用move构造函数是合法,因为它是返回值。

现在,在不调用std::move (或等效的强制转换)的情况下,使用左值调用A func(A &&a)是非常困难的。因此,从技术上讲,隐式移动&&类型的参数应该是可以的。但是标准委员会希望移动对于&&类型是显式的,只是为了确保移动不会隐式地发生在此函数的范围内。也就是说,它不能使用关于&&来自何处的函数外部知识。

一般来说,你应该只在两种情况下通过&&获取参数:要么你正在编写一个移动构造函数(或者移动赋值操作符,但即使是这样也可以通过值来完成),或者你正在编写一个转发函数。可能还有其他几种情况,但除非您有特殊的想法,否则不应将&&应用于某个类型。如果A是可移动类型,则只需按值获取。

票数 28
EN

Stack Overflow用户

发布于 2012-03-20 07:24:57

在第一种情况下,编译器知道a正在消失,没有任何东西能够附着在它上面:显然,这个对象可以被移走,如果不是这样,它将被销毁。在第二种情况下,rvalue引用表示允许从对象中移动,并且调用者不希望对象停留在原地。然而,这是函数的选择,它是否利用这个权限,可能有一些原因,函数有时想要离开参数,有时不想。如果编译器可以自由地移出这个对象,那么就没有办法阻止编译器这样做。然而,使用std::move(a)已经有了一种方法来指示它希望从对象中移动。

标准中的一般规则是编译器只会隐式地移动已知会消失的对象。当一个右值引用进来时,编译器并不真的知道对象将要离开:如果它被显式地std::move()ed,它实际上会留在原处。

票数 5
EN

Stack Overflow用户

发布于 2019-10-19 09:04:07

这是由P0527P1825为C++20修复的。将函数参数绑定到右值引用的唯一方法是让源成为临时值,或者让调用者显式地将非临时值转换为右值(例如,使用std::move)。因此,这种“强制优化”被认为是安全的。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9779079

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档