【问题标题】:c++ Return Value Optizationc++ 返回值优化
【发布时间】:2017-07-13 14:18:25
【问题描述】:

我希望有人能阐明 RVO 在 g++ 中的作用。我有一些需要修改的第三方软件,我想尽可能地对其进行优化,但我无法弄清楚 RVO 究竟做了什么,以及它何时启动。我目前的结构看起来像:

class Foo {
private:
    Bar     myBar;
public:
    Bar &getBar() { return myBar; };
};

调用者通常使用它的地方:

int x = foo.getBar().getX();

因为返回是一个引用,所以不需要结构的副本,这对性能来说很好。

我需要修改Foo 以使用Bar2 而不是Bar 作为其内部结构,但是,我需要保持getBar() 接口可供第三方调用者使用。我有一个函数convertBar2ToBar(const struct Bar2 &bar2, struct Bar &bar),可以高效的在两种结构类型之间进行转换,但是我担心,好像我这样做了:

Bar& Foo::getBar() { Bar rt; convertBar2ToBar(myBar2, rt); return rt }

然后,这将返回对堆栈上的变量的引用,该变量可以随意书写。我也可以修改程序以返回rt 的副本,如下所示:

Bar Foo::getBar() { Bar rt; convertBar2ToBar(myBar2, rt); return rt }

但现在我担心我的Foo.getBar().getX() 会很慢,因为它必须将Bar2 转换为rt(不可避免),然后将“rt”复制到调用者的本地上下文中(可以避免???)...我不清楚 RVO 是否可以防止复制,如果可以,幕后到底发生了什么。

【问题讨论】:

  • 首先不要担心性能问题,那只会导致过早优化,这通常很糟糕。而是尝试制作一个漂亮的、工作的、可读的、文档齐全的、注释良好的、可维护的程序。如果优化的发布版本的性能不是“足够好”(并且大多数时候“足够好”是足够好),那么测量、基准测试和配置文件以找到热点和瓶颈并仅 修复那些,与 cmets 一起了解您为什么这样做,以及代码在做什么。
  • 直觉是最糟糕的优化指南。测量和比较。例如,它可能看起来像是返回一个最优引用,但您是否考虑过取消引用的潜在成本?
  • 您说您必须保持getBar() 接口不变,但您也不应该将其返回类型从对值的引用更改。这可能会破坏调用者
  • 我更担心将返回类型从引用更改为副本。在我看来,这与您声明的保留界面的目标相矛盾。
  • Bar Foo::getBar() 和 Bar & Foo::getBar() 是完全不同的函数。调用者对这两种声明会有不同的期望。例如,假设Bar 有一些公共int x 成员。如果您删除 myFoo.getBar().x += 1; 之类的参考代码,可能会静默停止工作。

标签: c++ reference rvo


【解决方案1】:

我不清楚RVO是否可以防止复制

是的,这就是它的目的。

此外,从 C++17 开始,需要防止复制。
(抱歉,不是;那是为了返回一个纯右值;不过,您实际上可以依赖 NRVO)

如果复制品的价格足够昂贵,一开始就可以关心这些,那么它可能也应该是可移动的,在这种情况下,我们再次不关心成本。

如果是这样,引擎盖下到底发生了什么。

没关系。

但是,在您的 2017 年 PC 上,粗略地说,rt 将在调用者的堆栈框架中“创建”,而不是在此处本地创建。因此,根本不需要副本。

(事实上,不要返回对局部变量的引用。)

【讨论】:

  • 当你说movable时,你指的是什么?
  • @John:谷歌“C++ 移动语义”或转到你的 C++11 书中关于“移动语义”一章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
相关资源
最近更新 更多