什么时候应该通过const引用选择复制省略而不是传递参数?

时间:2012-07-07 09:01:11

标签: c++ c++11 lvalue rvalue rvo

  

可能重复:
  Is pass-by-value a reasonable default in C++11?

我正在阅读Dave Abrahams关于复制省略和RVO的Want Speed? Pass by Value.。而且我想知道为什么我们需要复制省略?

我被告知过多次你应该通过const引用传递函数参数以避免复制(我读过的几乎每一本c ++书都告诉我这个)。

假设我们有两个功能:

int f1(const string &s);
int f2(string s);

如果实际参数是右值,则两个函数都将避免复制。但如果实际参数是左值,则只能在f1中避免复制,而不是在f2中。那么为什么我们需要这个功能呢?

3 个答案:

答案 0 :(得分:11)

如果您还需要副本,请按值传递。是否选择f1的签名或f2的签名取决于函数的内容。例如,在这种情况下,您将使用const引用:

int f1(const string& s) {
    return s.size();
}

但在这种情况下你会通过值传递:

int f2(string s) {
    sort(s.begin(), s.end());
    s.erase(unique(s.begin(), s.end()), s.end());
    return s.size();
}

因为替代方案是:

int f2(const string& s) {
    string temp(s);
    sort(temp.begin(), temp.end());
    temp.erase(unique(temp.begin(), temp.end()), temp.end());
    return temp.size();
}

答案 1 :(得分:1)

RVO不适用于您的示例,因为返回值为int

string f1(const string &s) {
    string ret = s; // always makes a copy
    ret += 'x';
    return ret; // makes a copy pre-C++11 if no RVO
}

Tally:在C ++ 03中有1-2个拷贝,在C ++ 11中只有1个拷贝(如果禁用了elision),这个动作可能会退化为std::string之外的其他类的副本。

string f2(string s) { // calling makes a copy if lvalue or no elision
    s += 'x';
    return s; // makes a copy pre-C++11 if no RVO
}

理货:C ++ 03中0-2份,或C ++ 11中0-1份。

正如其他人所说,当你想把对象作为一个纯值来操作时传递值,没有任何引用语义。

const &是一个熟悉的习语,但就语言语义而言,它有点像kludge。当你根本不想要参考时,你可以使用它; &仅用于使const在参数定义中有意义。如果您想修改参数(但仅限于本地),则const并不真正适用,&也会消失。

答案 2 :(得分:0)

f2通过其签名发出信号,无论你传递给我什么,我都会处理我自己的对象副本。有用,如果f2将以不可逆的方式修改对象(例如通过移动窃取它的资源),或者在某些并发方案中。不可否认,c ++ 11为(已经令人困惑的)c ++类型系统增加了新的混乱程度,但一旦你想到它就会有很多意义......