信任返回值优化

6

如何使用返回值优化
在现代编译器中,是否有任何情况可以信任优化,还是我应该始终采取安全的方式并返回某种类型的指针/使用引用作为参数?

是否已知有任何无法进行返回值优化的情况?看来对于编译器来说,返回值优化应该相当容易实现。


2
请记住,编译器可能会决定在特定情况下不执行RVO优化,因此您不仅需要相信编译器在有用时执行它,而且还需要相信它在不适当时不执行它。 - MSalters
澄清一下:不适用的常见情况是当返回的类型可以在寄存器中传递时,例如 Radians 类。RVO 技术使用在栈上分配的空间,因此具有访问内存的开销。 - MSalters
@MSalters 好的,很有趣。我感兴趣的优化基本上是避免例如复制 std::vector<> 这样的操作。 - Viktor Sehr
3个回答

8
无论启用还是禁用编译器优化(在大多数编译器中,即使禁用优化),都会发生RVO。NRVO稍微不太常见,但大多数编译器至少在启用优化时也会执行此优化。
你说得对,这种优化对编译器来说相当容易,这就是为什么编译器几乎总是这样做的原因。唯一无法进行优化的情况是优化不适用的情况:只有在返回未命名临时对象时才适用RVO。如果要返回具名局部变量,则应使用NRVO,虽然它对于编译器来说略微更复杂,但是现代编译器没有问题。

特别是,如果您有2个命名变量并在运行时选择要返回的变量,则编译器显然无法执行NRVO :) - Matthieu M.
马修,我假设对于两个未命名的出口也是同样适用的吗?(例如,"if (...) return A() else return B();") - Viktor Sehr
@Viktor:不是NRVO,而是RVO。只有其中一个会被构造。因此,两个代码路径都可以使用相同的内存,即为返回值保留的内存。这就是RVO的本质:直接在为其保留的内存中创建返回值。 - MSalters
Matthieu:不,如果有两个可能返回的变量,NRVO仍然是可能的。有时我的函数有一个“if”语句。在一个分支中,我构造了一个命名值,对其进行操作并返回它;在另一个分支中,我做同样的事情,但可能使用不同的构造函数。没有理由编译器不能优化它,但我很确定我的编译器不能(Visual C ++)。 - Qwertie

6

2
为了让它最有可能发生,您可以在返回语句中直接构造一个对象 [有没有人记得这个习语的名称 - 我忘了]:
Foo f() {
    ....
    return Foo( ... );
}

但是,就像所有的优化一样,编译器总是可以选择不这样做。最终,如果您需要返回一个值,没有其他选择,只能信任编译器-指针和引用无法胜任。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接