如何写移动,以便它可以被潜在优化? [英] How to write move so that it can potentially be optimized away?
问题描述
给定以下代码:
struct obj {
int i;
obj() : i(1) {}
obj(obj &&other) : i(other.i) {}
};
void f() {
obj o2(obj(obj(obj{})));
}
我希望发布版本只真正创建一个对象,从不调用移动构造函数因为结果与执行我的代码时一样就像。大多数代码不是那么简单,我可以想到几个难以预测的副作用,可以阻止优化器证明像一样:
I expect release builds to only really create one object and never call a move constructor because the result is the same as if my code was executed. Most code is not that simple though, I can think of a few hard to predict side effects that could stop the optimizer from proving the "as if":
- $ b $
- 在移动构造函数或析构函数中可能出现异常 $ b $ b
- 内部计数或缓存机制改变。
- changes to global or "outside" things in either the move constructor or destructor.
- potential exceptions in the move constructor or destructor (probably bad design anyway)
- internal counting or caching mechanisms changing.
由于我不经常使用这些,我的动作进出功能,后来被内联优化或我忘记了什么?
Since I don't use any of these often can I expect most of my moves in and out of functions which are later inlined to be optimized away or am I forgetting something?
PS我知道,只是因为优化是可能的并不意味着它将由任何给定的编译器。
P.S. I know that just because an optimization is possible does not mean it will be made by any given compiler.
推荐答案
真的有什么关于as-if规则。编译器允许删除移动和副本,即使他们有一些副作用。这是允许编译器执行的单个优化,可能会改变程序的结果。从§12.8/ 31开始:
This doesn't really have anything to do with the as-if rule. The compiler is allowed to elide moves and copies even if they have some side effect. It is the single optimization that a compiler is allowed to do that might change the result of your program. From §12.8/31:
当满足特定条件时,允许实现省略类对象的复制/即使该对象的复制/移动构造函数和/或析构函数有副作用。
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.
因此,编译器不必麻烦检查你的移动构造函数中发生了什么,它可能会摆脱任何移动在这里。为了演示这一点,请考虑以下示例:
So the compiler doesn't have to bother inspecting what happens inside your move constructor, it will likely get rid of any moves here anyway. To demonstrate this, consider the following example:
#include <iostream>
struct bad_mover
{
static int move_count;
bad_mover() = default;
bad_mover(bad_mover&& other) { move_count++; }
};
int bad_mover::move_count = 0;
int main(int argc, const char* argv[])
{
bad_mover b{bad_mover(bad_mover(bad_mover()))};
std::cout << "Move count: " << bad_mover::move_count << std::endl;
return 0;
}
-
c> g ++ -std = c ++ 0x :
Move count: 0
编译为 g ++ -std = c ++ 0x -fno-elide-constructors
:
Move count: 3
但是,我会问任何你提供的移动构造函数有额外副作用的原因。允许此优化而不考虑副作用的想法是,复制或移动构造函数不应执行除复制或移动之外的任何操作。
However, I would question any reason you have for providing a move constructor that has additional side effects. The idea in allowing this optimization regardless of side effects is that a copy or move constructor shouldn't do anything other than copy or move. The program with the copy or move should be exactly the same as without.
尽管如此,你调用 std :: move
。 std :: move
用于将左值表达式更改为右值表达式,但创建临时对象的表达式已经是一个右值表达式。
Nonetheless, your calls to std::move
are unnecessary. std::move
is used to change an lvalue expression to an rvalue expression, but an expression that creates a temporary object is already an rvalue expression.
这篇关于如何写移动,以便它可以被潜在优化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!