69

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

第一的:

string name();

第二:

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

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

第二种变体看起来很有效,但写起来让我哭了

string name;
john.name(name);

而不是简单

string name(john.name());

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

提前致谢。

4

7 回答 7

53

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

首先,干净的方法是正确的方法。在大多数情况下(通常在有意义的地方),编译器会消除不必要的副本。

编辑(2016 年 6 月 25 日)

不幸的是,David Abaraham 的网站似乎已经离线好几年了,并且那篇文章已经丢失了(没有可用的 archive.org 副本)。我冒昧地将我的本地副本作为 PDF 上传以供存档,可以在此处找到

于 2012-05-11T14:16:30.153 回答
27

使用第一个变体:

string name();

编译器很可能会优化掉任何不必要的副本。请参阅返回值优化

在 C++11 中,移动语义意味着即使编译器不执行 RVO,您也不执行完整复制。请参阅移动语义

还要记住,如果替代方案是

void name(std::string& s);

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

于 2012-05-11T14:17:03.447 回答
9

既然你想为你的类的一个字段创建一个吸气剂,也许你应该这样做:inline const std::string& name() const { return this->name; }

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

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

于 2012-05-11T14:23:31.560 回答
5

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

于 2012-05-11T14:17:39.457 回答
2

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

string name();

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

于 2012-05-11T14:17:30.067 回答
2

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

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

于 2012-05-11T14:19:00.140 回答
1

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

于 2012-05-11T14:17:07.830 回答