在C ++中返回字符串的最佳方法是什么?

时间:2012-05-11 14:14:10

标签: c++ string

我的问题很简单:如果我有一些类Man,我想定义返回man名称的成员函数,我更喜欢以下两种变体中的哪一种?

首先:

string name();

第二

void name(/* OUT */ string &name);

第一个变体效率低下,因为它会产生不必要的副本(局部变量 - >返回值 - >赋值左侧的变量)。

第二种变体看起来非常有效,但它让我哭泣

string name;
john.name(name);

而非简单

string name(john.name());

那么,我更喜欢哪种变体,以及效率和便利性/可读性之间的适当权衡是什么?

提前致谢。

7 个答案:

答案 0 :(得分:52)

这是一个很好的问题,而且你问它的事实表明你正在关注你的代码。然而,好消息是,在这种特殊情况下,有一个简单的出路。

第一个干净的方法是正确的方法。 The compiler will eliminate unnecessary copies,在大多数情况下(通常在有意义的地方)。

编辑(2016年6月25日)

不幸的是,似乎David Abaraham的网站已经离线了几年了,而且这篇文章已经遗失给了ethers(没有archive.org副本可用)。我冒昧地将我的本地副本上传为PDF用于存档目的,并can be found here

答案 1 :(得分:25)

使用第一个变体:

string name();

编译器很可能会优化出任何不必要的副本。请参阅return value optimization

在C ++ 11中,移动语义意味着即使编译器不执行RVO也不会执行完整拷贝。请参阅move semantics

另外请记住,如果替代方案是

void name(std::string& s);

然后你必须非常清楚地指明s会发生什么以及传递给函数时它可以具有什么值,并且可能要么进行大量的有效性检查,要么只是完全覆盖输入。

答案 2 :(得分:9)

既然您想为班级的某个领域创建一个getter,也许你应该这样:inline const std::string& name() const { return this->name; }

由于名称作为const引用返回,因此不会在类外部进行修改,也不会通过返回名称来创建副本。

之后,如果您想操纵名称,则必须复制。

答案 3 :(得分:5)

我会选择第一个。返回值优化和C ++ 11将删除任何复制开销。

答案 4 :(得分:2)

由于我们有移动语义(在C ++ 11中),你可以使用它:

string name();

即使在C ++ 03中,这也差不多好,因为编译器可能会对此进行优化(搜索返回值优化)。

答案 5 :(得分:2)

优化规则#1:测量,优化,测量。或者,正如Knuth所说,“过早优化是所有邪恶的根源”。

除非您有强烈的迹象表明简单地返回std::string会显着影响您的软件的性能,否则就这样做。如果您可以衡量产生重大影响,请找到关键路径,并优化 。不要进行任何有趣的,项目范围的“优化”,这可能会导致很少或没有性能优势,但会对代码的可读性,可维护性和健壮性产生负面影响。

答案 6 :(得分:1)

我认为你应该使用第一个变体。因为这是简单的getter方法,所以在任何地方都使用这种getter / setter方法。