【发布时间】: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;之类的参考代码,可能会静默停止工作。