返回值优化和副作用 [英] Return value optimizations and side-effects

查看:197
本文介绍了返回值优化和副作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

返回值优化(RVO)是一种涉及复制精度的优化技术,它消除了在某些情况下创建用于保存函数返回值的临时对象。我理解RVO的一般好处,但我有几个问题。

Return value optimization (RVO) is an optimization technique involving copy elision, which eliminates the temporary object created to hold a function's return value in certain situations. I understand the benefit of RVO in general, but I have a couple of questions.

该标准在此工作草案(强调我的)。

The standard says the following about it in §12.8, paragraph 32 of this working draft (emphasis mine).


即使该对象的复制/移动构造函数和/或析构函数具有副作用,也允许实现省略类对象的复制/移动构造。在这种情况下,实现将省略的复制/移动操作的源和目标视为简单的两种不同的引用同一对象的方式,并且该对象的销毁发生在当两个对象将被

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.

然后列出一些条件,当实现可以执行这个优化。

It then lists a number of criteria when the implementation may perform this optimization.

我对此潜在优化有几个问题:

I have a couple of questions regarding this potential optimization:


  1. 我习惯于优化被约束,使得它们不能改变可观察的行为。此限制似乎不适用于RVO。 我需要担心标准中提及的副作用吗?存在可能导致麻烦的情况吗?

  1. I am used to optimizations being constrained such that they cannot change observable behaviour. This restriction does not seem to apply to RVO. Do I ever need to worry about the side effects mentioned in the standard? Do corner cases exist where this might cause trouble?

我作为程序员需要做什么(或不做)允许执行此优化?例如,以下禁止使用复制elision(由于 move ):

What do I as a programmer need to do (or not do) to allow this optimization to be performed? For example, does the following prohibit the use of copy elision (due to the move):



std::vector<double> foo(int bar){
    std::vector<double> quux(bar,0);
    return std::move(quux);
}



编辑



我将此发布为一个新问题,因为我提到的具体问题在其他相关问题中没有直接回答。

Edit

I posted this as a new question because the specific questions I mentioned are not directly answered in other, related questions.

推荐答案

$ b

我习惯于优化被约束,使得它们不能改变可观察的行为。

I am used to optimizations being constrained such that they cannot change observable behaviour.


这是正确的。作为一般规则(称为 as-if 规则),如果更改不可见,编译器可以更改代码。

This is correct. As a general rule -- known as the as-if rule -- compilers can change code if the change is not observable.



这种限制似乎不适用于RVO。

This restriction does not seem to apply to RVO.


是的。在OP中引用的子句给予 as-if 规则的例外,并且允许省略复制构造,即使其具有副作用。注意,RVO只是复制检测的一种情况(C ++ 11 12.8 / 31中的第一个要点)。

Yes. The clause quoted in the OP gives an exception to the as-if rule and allows copy construction to be omitted, even when it has side effects. Notice that the RVO is just one case of copy-elision (the first bullet point in C++11 12.8/31).



我是否需要担心标准中提及的副作用?

Do I ever need to worry about the side effects mentioned in the standard?


如果复制构造函数具有副作用,使得执行时的复制精度导致问题,那么您应该重新考虑设计。如果这不是你的代码,你应该考虑一个更好的选择。

If the copy constructor has side effects such that copy elision when performed causes a problem, then you should reconsider the design. If this is not your code, you should probably consider a better alternative.



What do I as a programmer need to do (or not do) to allow this optimization to be performed?


基本上,如果要执行(或不执行)可能,返回与函数返回类型相同的cv无限制类型的局部变量(或临时)。这允许RVO但不实施它(编译器可能不执行RVO)。

Basically, if possible, return a local variable (or temporary) with the same cv unqualified type as the function return type. This allows RVO but doens't enforce it (the compiler might not perform RVO).



以下禁止使用复制检查(由于移动):

For example, does the following prohibit the use of copy elision (due to the move):




// notice that I fixed the OP's example by adding <double>
std::vector<double> foo(int bar){
    std::vector<double> quux(bar, 0);
    return std::move(quux);
}

是的,因为您不返回局部变量的名称。

Yes, it does because you're not returning the name of a local variable. This

std::vector<double> foo(int bar){
    std::vector<double> quux(bar,0);
    return quux;
}

允许RVO。可能担心如果不执行RVO,那么移动比应对更好(这将解释上面 std :: move 的使用)。不要担心。所有主要编译器都会在这里做RVO(至少在发布版本中)。即使编译器不执行RVO但满足RVO的条件,它将尝试执行移动,而不是副本。总之,使用上面的 std :: move 肯定会移动。

allows RVO. One might be worried that if RVO is not performed then moving is better than coping (which would explain the use of std::move above). Don't worry about that. All major compilers will do the RVO here (at least in release build). Even if a compiler doesn't do RVO but the conditions for RVO are met then it will try to do a move rather than a copy. In summary, using std::move above will certainly make a move. Not using it will likely neither copy nor move anything and, in the worst (unlikely) case, will move.

更新:由于haohaolee的使用方式不同,因此不会复制或移动任何内容,但是,我把它们放在这里,因为他们建议一个想法可能适用于没有一个构造函数的一个想法采取一个 std :: initializer_list (见底部的参考)。对于 std :: vector ,haohaolee发现了一个解决方法。)

(Update: As haohaolee's pointed out (see comments), the following paragraphs are not correct. However, I leave them here because they suggest an idea that might work for classes that don't have a constructor taking a std::initializer_list (see the reference at the bottom). For std::vector, haohaolee found a workaround.)

在这个例子中,你可以强制RVO(严格地说,这不再是RVO,但让我们继续调用这种方式为简单)通过返回一个 braced-init-list 可以创建:

In this example you can force the RVO (strict speaking this is no longer RVO but let's keep calling this way for simplicity) by returning a braced-init-list from which the return type can be created:

std::vector<double> foo(int bar){
    return {bar, 0}; // <-- This doesn't work. Next line shows a workaround:
    // return {bar, 0.0, std::vector<double>::allocator_type{}};
}

查看此 post and R。 Martinho Fernandes 精彩的回答

See this post and R. Martinho Fernandes's brilliant answer.

小心点!返回类型为 std :: vector< int> 上面的最后一个代码与原始代码有不同的行为。 (这是另一个故事。)

Be carefull! Have the return type been std::vector<int> the last code above would have a different behavior from the original. (This is another story.)

这篇关于返回值优化和副作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆