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


67

我的问题很简单:如果我有一个Man类,并且我想定义返回man名的成员函数,我应该选择以下两个变体中的哪个?

第一:

string name();

第二:

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

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

第二个变种看起来很有效,但是让我哭泣

string name;
john.name(name);

而不是简单

string name(john.name());

那么,我应该选择哪种变体?在效率和便利性/可读性之间应该如何取舍?

提前致谢。


7
侧面说明,因为name()看起来像一个查询使它conststring name() const;
hmjd 2012年

@hmjd为什么第一个const?返回的对象最终属于客户端,他应该自由地处理他想要的对象。
詹姆斯·坎泽

2
@JamesKanze,这不是签名的一部分,而是我的评论,其后跟一个“:”。
hmjd 2012年

如果仅仅是访问相应成员变量的简单getter,那么aconst std::string&可能是一个更好的主意。
克里斯蒂安·劳

@hmjd对不起,那么。在我使用的字体中,:根本无法很好地显示出来。
詹姆斯·坎泽

Answers:


53

这是一个很好的问题,您所要求的事实表明您正在关注代码。但是,好消息是,在这种特定情况下,有一个简单的出路。

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

编辑(6/25/2016)

不幸的是,David Abaraham的站点似乎已经离线了几年,并且该文章已经丢失了以太币(没有可用的archive.org副本)。我出于存档目的将自己的本地副本以PDF格式上传,因此可以在此处找到


是的,这是一篇写得很好的文章,确实打在了头上。
Mahmoud Al-Qudsi'5

谢谢!我读过这篇文章,感到非常困惑,但是确实可以清除所有内容。现在我必须清理我的有效代码=)
tonytony 2012年

当然,对于重量级很重的变量,我总是使用“第二个变量”。我觉得这种方法甚至可以自我注释,因为读者会认为数据类型很重。至少,我的意见。
user606723

26

使用第一个变体:

string name();

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

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

还请记住,如果替代方法是

void name(std::string& s);

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


9

由于您要为课程的某个字段创建一个吸气剂,因此也许应该这样: inline const std::string& name() const { return this->name; }

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

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


感谢你的回答!这是有道理的,但是我考虑了在函数内部计算名称时的一些情况,例如,“ fullname()”函数返回的是姓氏和名字。
tonytony 2012年

2
是的,在这种情况下,您将必须返回该值,因为从函数返回后,对局部变量的引用将无效。您的问题的另一种选择是,在每次修改名字或姓氏时都可以计算全名(可以在setNamesetFirstName方法中进行此操作),并将其存储在全名字段中。这样,您不必在每次调用时都重新计算全名fullname(),只需要返回对全名字段的const引用(如我的回答中所述)。
Mesop 2012年

5

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


2

由于我们具有移动语义(在C ++ 11中),因此可以使用以下代码:

string name();

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


2

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

除非您有充分的迹象表明简单地返回std::string将大大影响软件的性能,否则请这样做。如果你能衡量一个显著的影响,找到关键路径,优化。不要进行任何有趣的,在项目范围内的“优化”,这可能几乎不会带来性能好处,但会对代码的可读性,可维护性和健壮性产生负面影响。


1

我认为您应该使用第一个变体。因为这是简单的吸气剂方法,并且这种吸气剂/设置器方法随处可见。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.