给定以下代码:
struct obj {
int i;
obj() : i(1) {}
obj(obj &&other) : i(other.i) {}
};
void f() {
obj o2(obj(obj(obj{})));
}
我希望发布版本只真正创建一个对象并且永远不会调用 move 构造函数,因为结果就好像我的代码被执行了一样。虽然大多数代码并不是那么简单,但我可以想到一些难以预测的副作用,这些副作用可能会阻止优化器证明“好像”:
- 在 move 构造函数或析构函数中更改全局或“外部”事物。
- move 构造函数或析构函数中的潜在异常(无论如何可能是糟糕的设计)
- 内部计数或缓存机制发生变化。
由于我不经常使用其中任何一个,我是否可以期望我大部分进出功能的 move ,这些功能后来被内联优化掉,或者我忘记了什么?
附言我知道仅仅因为优化是可能的并不意味着任何给定的编译器都会进行优化。
最佳答案
这实际上与假设规则没有任何关系。允许编译器省略 move 和复制,即使它们有一些副作用。这是允许编译器执行的单一优化,可能会改变程序的结果。来自§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.
因此编译器不必费心检查你的 move 构造函数中发生了什么,它很可能会在这里摆脱任何 move 。为了证明这一点,请考虑以下示例:
#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;
}
使用
g++ -std=c++0x
编译:Move count: 0
使用
g++ -std=c++0x -fno-elide-constructors
编译:Move count: 3
但是,我会质疑您提供具有额外副作用的 move 构造函数的任何理由。允许这种优化而不考虑副作用的想法是复制或 move 构造函数不应该做除复制或 move 之外的任何事情。复制或 move 的程序应该与没有复制或 move 的程序完全相同。
尽管如此,您对 std::move
的调用是不必要的。 std::move
用于将左值表达式更改为右值表达式,但创建临时对象的表达式已经是右值表达式。
关于c++ - 如何编写 move 以便它可以被优化掉?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15040784/