如何写移动,以便它可以被潜在优化? [英] How to write move so that it can potentially be optimized away?

查看:120
本文介绍了如何写移动,以便它可以被潜在优化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下代码:

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 $
  1. 在移动构造函数或析构函数中可能出现异常
  2. $ b $ b
  3. 内部计数或缓存机制改变。

  1. changes to global or "outside" things in either the move constructor or destructor.
  2. potential exceptions in the move constructor or destructor (probably bad design anyway)
  3. 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;
}




  1. 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屋!

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