2

Andrew Koenig 写了一篇标题为Some Optimizations are more important than Others的文章,其中包含以下两个函数定义:

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 对其进行测试时,这不是我所看到的。第一个函数移动语句中的对象sreturn而第二个函数复制对象。如果我将第二个函数中的 return 语句更改为return move(s);,那么在这两种情况下都将移动对象。

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

4

1 回答 1

6

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

  1. 是自动变量。
  2. 在函数的范围内声明,这样它们就保证在函数退出时被销毁。
  3. 是值类型的变量。

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

但是,如果您想知道为什么后者会更有效,它与移动的数量有关。

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

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

所以第一种情况有一个副本/移动和一个移动,而只有一个副本。因此,如果用户正在复制参数,由于额外的移动,您的第一种情况会变慢。

运动不是自由的。它可能很便宜(相对于复制而言),但它不是免费的。2 次移动比 1 次更昂贵。如果用户调用const&版本,这意味着他们要求复制字符串。所以他们得到一个副本,然后是一个几乎肯定会被忽略的动作。

就个人而言,我会权衡次要的效率提升与两次实现相同功能的严重头痛。在某些情况下,这可能是值得的。但我不会理所当然地这样做。

于 2013-08-24T10:35:08.600 回答