编译器优化

时间:2011-08-31 17:47:01

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

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

#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. copy ctor
  3. move ctor
  4. 析构函数
  5. 析构函数
  6. 析构函数
  7. 并且它是真的,但只有在关闭编译器优化时才 。当优化打开时,输出完全不同。打开优化后,输出为:

    1. 构造函数
    2. copy ctor
    3. 析构函数
    4. 析构函数
    5. 使用编译器优化,测试变量是返回变量。

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

      我一直被告知,返回一个导致额外复制构造函数的结构/类可以通过作为引用传入进行优化,但编译器正在为我做这些。那么返回一个仍被视为不良形式的结构?

4 个答案:

答案 0 :(得分:14)

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

标准特别允许优化,只要可以复制/移动(即,声明并可访问该方法)。

编译器中的实现通常称为返回值优化。有两种变化:

  • RVO :当您返回临时(return "aa" + someString;
  • NRVO :N为Named,当您返回名称为
  • 的对象时

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

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

// Bad
Foo foo;
bar(foo);

-- foo can be modified here


// Good
Foo const foo = bar();

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

答案 1 :(得分:4)

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

  

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

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

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