如何编写移动以便可以优化它?

odi*_*erd 1 c++ optimization move c++11

给出以下代码:

struct obj {
    int i;
    obj() : i(1) {}
    obj(obj &&other) : i(other.i) {}
};

void f() {
    obj o2(obj(obj(obj{})));
}
Run Code Online (Sandbox Code Playgroud)

我希望发布版本只有真正创造一个对象,并永远不会调用移动的构造,因为结果是一样的,就好像是执行我的代码.大多数代码并不是那么简单,我可以想到一些难以预测的副作用可能会阻止优化器证明"好像":

  1. 在移动构造函数或析构函数中更改为全局或"外部"事物.
  2. 移动构造函数或析构函数中的潜在异常(无论如何可能是糟糕的设计)
  3. 内部计数或缓存机制的变化.

因为我不经常使用这些中的任何一个,所以我可以期待我的大部分进出函数的进出被优化掉或忘记了什么?

PS我知道只是因为优化是可能的并不意味着它将由任何给定的编译器完成.

Jos*_*eld 7

这与as-if规则没有任何关系.即使编译器有一些副作用,也允许编译器忽略移动和复制.允许编译器执行的单一优化可能会更改程序的结果.从§12.8/ 31开始:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使该对象的复制/移动构造函数和/或析构函数具有副作用.

所以编译器不必费心检查移动构造函数中发生的事情,无论如何它都可能会摆脱任何移动.为了证明这一点,请考虑以下示例:

#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;
}
Run Code Online (Sandbox Code Playgroud)
  1. 编译g++ -std=c++0x:

    Move count: 0
    
    Run Code Online (Sandbox Code Playgroud)
  2. 编译g++ -std=c++0x -fno-elide-constructors:

    Move count: 3
    
    Run Code Online (Sandbox Code Playgroud)

但是,我会质疑你提供具有额外副作用的移动构造函数的任何原因.允许此优化而不考虑副作用的想法是复制或移动构造函数不应执行除复制或移动之外的任何操作.复制或移动的程序应与没有复制或移动完全相同.

尽管如此,您的电话std::move是不必要的.std::move用于将左值表达式更改为右值表达式,但创建临时对象的表达式已经是右值表达式.