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进行测试时,这不是我所看到的。第一个函数移动 s
语句中的对象return
,而第二个函数复制对象。如果我将第二个函数中的return语句更改为return move(s);
,那么在这两种情况下对象都将移动。
问题:return
语句中哪些参数可以自动移动?更具体地说,声明为非const rvalue-references的参数是否可以自动移动?
答案 0 :(得分:6)
可以通过return语句自动移动的唯一内容是:
#3删除了任何类型的引用。如果你想从参考文献中移动,你必须明确地说要从它移动。
但是,如果你想知道为什么后者会更有效率,那就与行动次数有关。
在第一种情况下,您将复制/移动到函数参数s
。用户必须将某些字符串复制或移动到参数中。然后参数的数据被移回。
在第二种情况下,你既没有复制也没有进入函数参数;它只是引用一个现有的对象。如果用户调用右值参考版本,则您只有一个副本 out 参数。
因此,第一个案例有一个副本/移动和一个移动,而不是一个副本。因此,如果用户正在复制参数,由于额外的移动,您的第一个案例将会变慢。
运动不是免费的。它可能便宜(相对于复制),但它不是免费。 2次移动比1更贵。如果用户调用const&
版本,这意味着他们要求复制字符串。所以他们得到一份副本,然后几乎肯定会被删除。
就个人而言,我会将较小的效率收益与两次实施相同功能的重大问题进行权衡。在某些情况下,它可能是值得的。但我当然不会这样做。