什么样的参数可以在返回语句中自动移动

What kind of parameters can be automatically moved in return statements?

本文关键字:语句 移动 返回 参数 什么样      更新时间:2023-10-16

Andrew Koenig写了一篇题为"某些优化比其他优化更重要"的文章,其中包含以下两个函数定义:

string rev(string s) {
    reverse(s.begin(), s.end());
    return s; // GCC-4.8 uses move constructor
}
string rev(string&& s) {
    reverse(s.begin(), s.end());
    return s; // GCC-4.8 uses copy constructor
}

文章暗示第二个函数(与const string&过载相结合)比第一个函数更有效。然而,当我用GCC-4.8测试它时,我并没有看到这一点。第一个函数return语句中移动对象s,而第二个函数复制对象。如果我将第二个函数中的return语句更改为return move(s);,那么在这两种情况下,对象都将被移动

问题:什么样的参数可以在return语句中自动移动?更具体地说,声明为非常量右值引用的参数是否可以自动移动

唯一可以通过return语句自动移动的变量是:

  1. 是自动变量
  2. 在函数的作用域中声明,从而保证它们在函数退出时被销毁
  3. 是值类型的变量

#3消除了任何类型的引用。如果你想从引用中移动,你必须明确地说要从它中移动

然而,如果你想知道为什么后者会更有效,这与移动次数有关。

在第一种情况下,您可以将复制/移动到函数参数s中。用户必须将一些字符串复制或移动到参数中。然后参数的数据被移回。

在第二种情况下,您既没有复制也没有移动到函数参数中;它只是引用一个现有的对象。如果用户调用右值引用版本,则会有一个参数的输出的副本。

因此,第一种情况有一个拷贝/移动和一个移动,而不是一个拷贝。因此,如果用户正在复制参数,由于额外的移动,您的第一种情况会更慢。

行动不是自由的。它可能便宜(相对于复制),但它不是免费的2步比1步贵。如果用户调用const&版本,则意味着他们要求复制字符串。因此,他们得到了一份副本,然后采取了几乎肯定会被取消的行动。

就我个人而言,我会权衡两次实现相同功能带来的微小效率提升和令人头疼的问题。在某些情况下,这可能是值得的。但我不会理所当然地这么做。