【问题标题】:C++ String output reference parameter or return value, is there an optimal approach?C++字符串输出引用参数或返回值,有没有最优的方法?
【发布时间】:2015-11-19 05:19:42
【问题描述】:

示例代码:

class Thingy
{
public:
    void doStuff(std::string&);
    std::string doStuff();
};

void Thingy::doStuff(std::string& str) {
    str = "stuff";
}

std::string Thingy::doStuff() {
    return "stuff";
}

int main(int argc, const char* args[])
{
    std::string name;
    Thingy thingy;
    thingy.doStuff(name);
    std::cout << name << " " << thingy.doStuff() << std::endl;
}

特别是对于字符串,这两种方法是否更有效,这种效率是否“值得”扭曲代码的可读性或一致性? (例如,如果不需要,我宁愿不创建 name 变量)

这是(归根结底)与本次讨论相关的字符串常量这一事实吗?

【问题讨论】:

  • 基本上答案和returning a std::vector一样。
  • 我更喜欢返回std::string,因为它更具可读性。您的编译器很可能会执行 RVO(返回值优化),即使不执行,也会使用其移动构造函数构造字符串。它不会显着降低效率。
  • 这是 [...] 与本次讨论相关的字符串常量。只要返回类型是std::string 而不是const std::string &amp;,区别就无关紧要了,因为最后你需要从一个常量char数组构造一个可变字符串。
  • @πάνταῥεῖ 这回答了我关于“字符串是否特殊”的问题。但我确实看到了将字符串作为返回类型和向量作为输出参数传递的趋势(可能是因为字符串更可能很短)

标签: c++ c++11 c++03


【解决方案1】:

std::string 上的写时复制语义不再被允许,因此,从表面上看,您可能认为按值返回字符串的计算成本很高,因为要进行深度复制。

但是,在 C++03 中,一个好的编译器会删除深层副本。在 C++11 中,将调用 move 构造函数。不会采取任何超值副本。

就我个人而言,我不喜欢将非const 引用传递给函数的模式,因为调用者并不能立即看出参数已被修改。您也不能将匿名临时传递给这样的函数(在这种情况下,您当然不想这样做)。编写返回字符串的函数会给您带来所有优点而没有缺点。

【讨论】:

  • 事实上,即使在 C++11 中,副本也会被忽略(当然,如果可以的话)而不是调用 move 构造函数。只有当省略失败时才会使用移动构造函数。
  • @SergeyA:你确定吗?这有标准的参考吗?
  • 我很确定 :)。至于标准,当然没有,因为标准中没有指定优化。但这是我所知道的所有 C++11 编译器的实际行为。事实上,很难想象其他情况,因为这意味着 C++11 的性能将比 C++03 更差——因为即使移动构造函数也比没有构造函数更昂贵。
  • 请注意,由于小字符串优化,使用小字符串移动可能不会比复制便宜。
【解决方案2】:

返回字符串方法更有效,因为它只值得一个字符串构造(由于 RVO)。对我来说也比较容易理解。

【讨论】:

  • 我不认为按值返回总是更有效(在这种特定情况下,它可能是,尽管一些编译器也可能内联“按引用调用”并输出完全相同的代码)。对于更复杂的函数,可能不会执行 RVO(取决于编译器),而可能会使用移动构造函数。无论如何,效率差异很小,所以这并不重要。
  • @Caninonos 在 C++03 中,没有移动构造函数,评估会改变吗?
  • @deworde 在 C++03 中,只要函数不太复杂(同样取决于编译器),RVO 仍可能会执行。但是,如果没有,则将调用复制构造函数(对于大向量或字符串,这样的调用可能很昂贵)。在那种情况下,传递引用(并对其进行变异)确实更有效并且可能是首选(在您的示例中,该函数非常简单,大多数编译器都会执行 RVO,所以这并不重要)。 (编辑:就个人而言,如果可能,我会避免使用 C++03 并返回值,而不是在我的函数中改变引用)
【解决方案3】:

如果字符串不长,那么按值返回也不是那么糟糕!特别是它允许使用“.”运算符连接事物。 此外,现在在 C++11 中,当出现 move constructor 时,与 按值返回 相关的性能问题已显着降低。

【讨论】:

  • 重复连接非常昂贵。
  • @Bathsheba 不使用移动构造函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多