C++ c++;返回值优化

C++ c++;返回值优化,c++,reference,rvo,C++,Reference,Rvo,我希望有人能解释一下RVO在g++中的作用。我有一些需要修改的第三方软件,我想尽可能地优化它,但我很难弄清楚RVO到底做什么,以及什么时候启动。我当前的结构类似于: class Foo { private: Bar myBar; public: Bar &getBar() { return myBar; }; }; 呼叫者通常这样使用它: int x = foo.getBar().getX(); 因为返回是一个引用,所以不需要结构的副本,这对于性能来说很好 我

我希望有人能解释一下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是否可以阻止复制,如果可以,引擎盖下到底发生了什么

我不清楚RVO是否能阻止复制

是的,这就是它的目的

此外,还需要防止从C++17开始的复制。
(抱歉,不,不是;这是用于返回prvalue的;不过,实际上您可以依赖NRVO)

如果复制品的价格足够高,一开始就需要考虑这些,那么它可能也应该是可移动的,在这种情况下,我们同样不关心成本

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

没关系

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

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

我不清楚RVO是否能阻止复制

是的,这就是它的目的

此外,还需要防止从C++17开始的复制。
(抱歉,不,不是;这是用于返回prvalue的;不过,实际上您可以依赖NRVO)

如果复制品的价格足够高,一开始就需要考虑这些,那么它可能也应该是可移动的,在这种情况下,我们同样不关心成本

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

没关系

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


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

首先不要担心性能,这只会导致过早优化,这通常是不好的。相反,试着做一个好的、工作的、可读的、有良好文档记录的、有良好注释的、可维护的程序。如果优化的发布版本的性能不够好(大多数情况下“足够好”就足够好),那么测量、基准测试和配置文件以找到热点和瓶颈并仅修复这些,并对您为什么这样做以及代码在做什么进行注释。直觉是最差的优化指南。测量和比较。例如,返回一个引用似乎是最优的,但您是否考虑了取消引用的潜在成本?您说必须保持
getBar()
接口的原样,但也不应该将其返回类型从引用更改为值。这可能会中断调用者,我更担心的是将返回类型从引用更改为副本。在我看来,这与您声明的保留接口的目标相矛盾。
Bar-Foo::getBar()
Bar&Foo::getBar()
是截然不同的函数。调用者对这两种声明的期望不同。例如,假设
Bar
有一些公共
intx
成员。如果删除参考代码,如
myFoo.getBar().x+=1可能会自动停止工作。首先不要担心性能,这只会导致过早的优化,这通常是不好的。相反,试着做一个好的、工作的、可读的、有良好文档记录的、有良好注释的、可维护的程序。如果优化的发布版本的性能不够好(大多数情况下“足够好”就足够好),那么测量、基准测试和配置文件以找到热点和瓶颈并仅修复这些,并对您为什么这样做以及代码在做什么进行注释。直觉是最差的优化指南。测量和比较。例如,返回一个引用似乎是最优的,但您是否考虑了取消引用的潜在成本?您说必须保持
getBar()
接口的原样,但也不应该将其返回类型从引用更改为值。这可能会中断调用者,我更担心的是将返回类型从引用更改为副本。在我看来,这与您声明的保留接口的目标相矛盾。
Bar-Foo::getBar()
Bar&Foo::getBar()
是截然不同的函数。调用者对这两种声明的期望不同。例如,假设
Bar
有一些公共
intx
成员。如果删除参考代码,如
myFoo.getBar().x+=1
可能会自动停止工作。当你说movable时,你指的是什么?@John:Google“C++移动语义”或转到你的C++11手册中关于“移动语义”的章节。当你说movable时,你指的是什么?@John:Google“C++移动语义”或转到你的C++11手册中关于“移动语义”的章节