在C ++中返回string的最好方法是什么?
我的问题很简单:如果我有一个类Man,并且想定义返回人名的成员函数,我更喜欢以下两个变体中的哪一个?
第一:
string name();
第二:
void name(/* OUT */ string &name);
第一个变种是低效的,因为它会产生不必要的拷贝(局部variables – >返回值 – >赋值左边的variables)。
第二个变种看起来非常有效,但是这让我哭了
string name; john.name(name);
而不是简单
string name(john.name());
那么,我更喜欢什么样的变体,效率和方便性/可读性之间有什么合适的取舍?
提前致谢。
这是一个很好的问题,而且你问的事实表明你正在关注你的代码。 不过,好消息是,在这个特殊情况下,有一个简单的办法。
第一,干净的方法是正确的做法。 编译器会在大多数情况下(通常在有意义的地方) 消除不必要的副本 。
编辑(6/25/2016)
不幸的是,David Abaraham的网站似乎已经离线了好几年了,而这篇文章已经被输给了ethers(没有archive.org的副本)。 为了档案的目的,我冒昧地把本地副本上传为PDF格式, 可以在这里find 。
使用第一个变体:
string name();
编译器很可能会优化任何不必要的副本。 请参阅返回值优化 。
在C ++ 11中,移动语义意味着即使编译器不执行RVO,也不会执行完整的副本。 请参阅移动语义 。
另外请记住,如果替代scheme是
void name(std::string& s);
那么你必须非常清楚地指定s
可能发生的事情,以及它传递给函数时可能具有的值,可能要么进行大量的有效性检查,要么完全覆盖input。
既然你想为你的类的字段创build一个getter,也许你应该这样做: inline const std::string& name() const { return this->name; }
inline const std::string& name() const { return this->name; }
由于该名称是作为一个const引用返回的,因此它不会在类外被修改,也不会通过返回名称来创build副本。
之后,如果你想操纵这个名字,你将不得不做一个副本。
我会去的第一个。 返回值优化和C ++ 11将删除任何复制开销。
由于我们有移动语义(在C ++ 11中),你可以使用这个:
string name();
即使在C ++ 03中,这也几乎是不错的,因为编译器可能会优化它( search返回值优化 )。
优化规则1: 测量 ,优化,测量。 或者,正如Knuth所说,“不成熟的优化是万恶之源”。
除非你有强烈的暗示,简单的返回std::string
会显着影响你的软件的性能,只要这样做。 如果您可以衡量重大影响,find关键path,并优化。 不要做任何有趣的项目范围的“优化”,这可能会导致很less或没有性能好处,但会对代码的可读性,可维护性和健壮性产生负面影响。
我认为你应该使用第一个变种。 因为这是简单的getter方法,并且这种getter / setter方法被使用到处。