【问题标题】:compiler optimization编译器优化
【发布时间】:2011-11-07 20:04:07
【问题描述】:

所以我有一个问题要问你。 :) 你能告诉我以下代码应该产生的输出吗?

#include <iostream>
struct Optimized
{
    Optimized() { std::cout << "ctor" << std::endl; }
    ~Optimized() { std::cout << "dtor" << std::endl; }
    Optimized(const Optimized& copy) { std::cout << "copy ctor" << std::endl; }
    Optimized(Optimized&& move) { std::cout << "move ctor" << std::endl; }
    const Optimized& operator=(const Optimized& rhs) { std::cout << "assignment operator" << std::endl; return *this; }
    Optimized& operator=(Optimized&& lhs) { std::cout << "move assignment operator" << std::endl; return *this; }
};

Optimized TestFunction()
{
    Optimized a;
    Optimized b = a;
    return b;
}

int main(int argc, char* argv[])
{
    Optimized test = TestFunction();
    return 0;
}

我的第一反应是:

  1. 演员
  2. 复制ctor
  3. 移动 ctor
  4. dtor
  5. dtor
  6. dtor

确实如此,但只有在关闭编译器优化时。当优化打开时,输出完全不同。开启优化后,输出为:

  1. 演员
  2. 复制ctor
  3. dtor
  4. dtor

通过编译器优化,测试变量是返回变量。

我的问题是,什么条件会导致不能以这种方式优化?

我一直被教导,返回一个导致额外复制构造函数的结构/类可以通过作为引用传递来更好地优化,但编译器正在为我这样做。那么返回一个结构仍然被认为是错误的形式吗?

【问题讨论】:

  • 这叫做返回值优化。
  • 将您的问题重新格式化为更多采用这种格式会有所帮助:这是我的代码“”,这是我的结果。有什么办法可以得到“”
  • @mydogisbox:我发现这个问题其实很清楚。
  • 但是@Mydogisbox,它已经是那种格式了。它显示了代码。它显示了预期结果和实际结果。然后它询问产生预期结果的必要条件。
  • @Rob Kennedy 该帖子以一个问题开始,然后在帖子中得到回答。最好不要这样做以减少问题的混乱。

标签: c++ visual-studio-2010 optimization g++


【解决方案1】:

这称为复制省略,是一种特殊处理,而不是复制/移动。

标准明确允许优化,只要可以复制/移动(即,方法已声明且可访问)。

在这种情况下,编译器中的实现通常称为返回值优化。有两种变体:

  • RVO:当你返回一个临时的 (return "aa" + someString;)
  • NRVO:N 代表命名,当你返回一个有名字的对象时

两者都由主要编译器实现,但后者可能只在更高的优化级别上启动,因为它更难检测。

因此,回答您关于返回结构的问题:我会推荐它。考虑:

// Bad
Foo foo;
bar(foo);

-- foo can be modified here


// Good
Foo const foo = bar();

后者不仅更清晰,还允许const强制执行!

【讨论】:

  • 我从未见过它被称为未命名的 RVO。它通常被称为 RVO。 RVO 和 NRVO。
  • @DeadMG:是的,我经常希望它是 RVO = URVO + NRVO,因为 RVO 代表这里的通用和特殊......已更正以匹配用法。
【解决方案2】:

两种输出都是允许的。 C++03 语言标准在第 12.8/15 条中说:

当满足某些条件时,允许实现省略类对象的复制构造, 即使对象的复制构造函数和/或析构函数有副作用。在这种情况下,实施 将省略的复制操作的源和目标简单地视为两种不同的引用方式 同一个对象,并且该对象的销毁发生在两个对象的较晚时间 没有优化就会被破坏。111) 复制操作的这种省略是允许的 以下情况(可合并消除多个副本):

  • 在具有类返回类型的函数中的 return 语句中,当表达式是 具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象,副本 可以通过将自动对象直接构造到函数的返回值中来省略操作
  • 当尚未绑定到引用 (12.2) 的临时类对象将被复制到类时 具有相同 cv-unqualified 类型的对象,可以通过构造临时省略复制操作 将对象直接放入省略副本的目标中

【讨论】:

  • +1 even if the copy constructor and/or destructor for the object have side effects 不知道。这似乎有潜在的问题......
【解决方案3】:

此代码将产生的输出是不可预测的,因为语言规范明确允许可选地消除(省略)类对象的“不必要”临时副本,即使它们的复制构造函数有副作用。

这是否会发生可能取决于多种因素,包括编译器优化设置。

在我看来,将上述复制省略称为“优化”并不完全正确(尽管在这里使用这个术语的愿望是完全可以理解的,并且它被广泛用于此目的)。我想说的是,优化这个术语应该保留给编译器偏离抽象C++机器的行为同时保留可观察的情况程序的行为。换句话说,真正的优化意味着违反语言规范的抽象要求。由于在这种情况下没有违规(标准明确允许复制省略),因此没有真正的“优化”。我们在这里观察到的是 C++ 语言在其抽象级别是如何工作的。根本不需要涉及“优化”的概念。

【讨论】:

    【解决方案4】:

    即使在按值传回时,编译器也可以使用 返回值优化 优化额外的副本。 http://en.wikipedia.org/wiki/Return_value_optimization

    【讨论】:

      猜你喜欢
      • 2014-02-21
      • 2011-08-24
      • 2012-02-12
      • 2011-12-29
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多