C ++构造函数成员分配优化

时间:2017-12-28 05:46:46

标签: c++

我想知道C ++编译器是否有可能在这种情况下进行优化。假设我们有一个类:

class Foo {
public:
  Foo() : a(10), b(11), c(12) {};
  int a;
  int b;
  int c;
};

我使用这个类:

int main(int argc, char *argv[]) {
  Foo f;
  f.a = 50;
  f.b = 51;
  f.c = 52;
  return 0;
}

编译器是否会生成代码以将abc设置为各自的默认值10,11,12,然后将它们设置为50,51,52 ?或者是否允许延迟分配这些初始值,而只是稍后分配值(50,51,52),因为写入之间没有读取?基本上它必须生成代码来写这六个值,还是可以优化为三个?

如果是这样,这是否也适用于更复杂的类型(结构,类)?它叫什么,我在哪里可以阅读更多相关信息?

如果没有,为什么不呢?

3 个答案:

答案 0 :(得分:2)

这显然取决于编译器 - 但肯定至少有一些编译器可以并且将消除死存储。实际上,根据您使用结果的方式,编译器可能会消除所有存储,无论是死还是其他。

例如,如果我们完全按照现在的方式编译您的代码,我们最终会得到这样的汇编语言:

xor eax, eax
ret

就是这样 - 因为你从不使用你存储的任何值,它完全消除了处理这些值的所有代码。剩下的就是main返回0这一事实,因此它只会生成main的代码以返回零。

这可能不是你关心的一个案例,所以让我们稍微扩展一下代码,以显示更接近你可能关心的东西。

#include <iostream>

class Foo {
public:
  Foo() : a(10), b(11), c(12) {};
  int a;
  int b;
  int c;

  friend std::ostream &operator<<(std::ostream &os, Foo const &f) {
      return os << "(" << f.a << ", " << f.b << ", " << f.c << ")";
  }
};

int main() {
  Foo f;
  f.a = 50;
  f.b = 51;
  f.c = 52;

  std::cout << f << "\n";
}

在这种情况下,编译器仍然会消除所涉及的所有存储,并生成代码以直接写出我们在源代码中作为文字提供的值:

mov esi, 50
mov edi, OFFSET FLAT:std::cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)

[和51和52重复相同的序列]。

参考:

Godbolt

答案 1 :(得分:1)

是的,编译器可以优化以删除初始化。此技术称为dead store优化。确定是否发生死存储是data-flow analysis的一部分。

答案 2 :(得分:-2)

首先将三个值分配给a,b和c,然后将它们更改为后面指定的值。

这是因为在c ++中,执行是逐行的。因此,首先声明对象,并在声明后立即获取构造函数指定的值。之后,a,b和c值会发生变化。

优化它,您可以使用带有默认参数的构造函数,例如

class Foo{
public:
int a, b, c;
Foo(x = 10, y = 11, z = 12){
   a = x;
   b = y;
   c = z;
}
};

int main(){
Foo f; //a gets 10, b gets 11, c gets 12
Foo fi(51, 52, 53); //a gets 51, b gets 52, c gets 53
}