【发布时间】:2010-09-13 04:18:56
【问题描述】:
在重构一些代码时,我遇到了一些返回 std::string 的 getter 方法。例如这样的事情:
class foo
{
private:
std::string name_;
public:
std::string name()
{
return name_;
}
};
当然,getter 会更好地返回const std::string&?当前方法正在返回一个效率不高的副本。返回一个 const 引用会导致任何问题吗?
【问题讨论】:
-
谁说没有效率。在 std::string 上做了很多工作来使这个操作高效。传递引用和传递字符串是有区别的,但实际区别通常是微不足道的。
-
@Loki:没有人说它会高效,事实上最新版本的 C++ 说它可能会高效。使该代码合理高效的唯一优化是引用计数的 std::string。但是,许多 STL 实现不进行引用计数,因为在现代多核 CPU 上,管理引用计数比您想象的要慢得多。所以是的,返回副本要慢得多。多年来,GCC 和微软的 STL 都没有对 std::string 进行引用计数。
-
@seanmiddleditch:在你假设之前总是测量(这就是我所说的)。编译器还可以应用许多其他优化:内联和复制省略是两个可以将成本降低到零的。
-
@Loki:是的,这是个好建议;总是配置文件。同样好的建议是了解“假设”和“事实”之间的区别。我向您保证,Rob 的代码在任何符合 C++ 编译器的实现中都不会导致零开销。该语言要求从 foo::name() 返回时必须至少调用一次复制构造函数,即使使用内联(对何时调用构造函数没有影响)、复制省略(不适用于此代码)和 RVO(可能会减少额外的复制构造函数调用,但不会全部消除)。
-
@Loki:我 确实 尝试在 GCC 4.6 和 VC 10 上测量它,都打开了最大优化,并得到相同的结果:复制构造函数是调用。即使您考虑 as-if 规则,这也是“明显”的结果,因为 std::string 的复制构造函数实际上有副作用:它要么创建一个全新的字符数组和字符串的副本,要么它操纵引用计数值(取决于实现)。请注意,在引用计数的 impl 上进行足够简单的微基准测试可能不会在这里给您“真实”的结果,这是我第一次尝试在 GCC 上遇到的。