什么样的参数可以在return语句中自动移动?

nos*_*sid 2 c++ c++11

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
}
Run Code Online (Sandbox Code Playgroud)

文章暗示第二个函数(与const string&重载相结合)比第一个函数更有效.然而,当我用GCC-4.8进行测试时,这不是我所看到的.第一个函数在语句中移动对象s,return而第二个函数复制对象.如果我将第二个函数中的return语句更改为return move(s);,则在两种情况下都将移动该对象.

问题:可以在语句中自动移动哪些参数return?更具体地说,声明为非const rvalue-references的参数是否可以自动移动

Nic*_*las 6

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

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

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

但是,如果你想知道为什么后者会更有效率,那么它与移动次数有关.

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

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

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

运动不是免费的.它可能便宜(相对于复制),但它不是免费的.2个移动比1更贵.如果用户调用const&版本,则表示他们要求复制字符串.所以他们得到一份副本,然后几乎肯定会被删除.

就个人而言,我会将较小的效率增益与两次实施相同功能的重大问题进行权衡.在某些情况下,它可能是值得的.但我不会理所当然地这样做.