9

可能重复:
按值传递是 C++11 中合理的默认值吗?

我在读想要速度?按值传递。戴夫亚伯拉罕关于复制省略和 RVO。我想知道为什么我们需要复制省略?

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

假设我们有两个函数:

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

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

4

3 回答 3

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();
}
于 2012-07-07T09:07:21.173 回答
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 个,加上(如果禁用省略)一个移动可能会退化为其他类的副本,而不是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
}

Tally:在 C++03 中为 0-2 个副本,在 C++11 中为 0-1 个。

正如其他人所说,当您想将对象作为纯值进行操作时,按值传递,没有任何引用语义。

const &是一个熟悉的习语,但就语言语义而言,它有点杂乱无章。当您根本不需要参考时使用它;&只是为了使参数const定义有意义。如果您想修改参数(但仅限于本地),则const实际上并不适用,并且也会&退出。

于 2012-07-07T09:08:50.657 回答
0

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

于 2012-07-07T09:14:39.487 回答