C 构造函数成员分配优化

C++ Constructor member assignment optimization

本文关键字:优化 分配 成员 构造函数      更新时间:2023-10-16

我想知道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),因为文字之间没有读数?基本上,它必须生成代码来编写这六个值,还是可以优化三个?

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

如果不是,为什么不呢?

这显然取决于编译器 - 但是至少有一些编译器可以并且可以消除死者的存储。实际上,根据您的使用方式,编译器可能会消除所有所有商店,即死亡或其他方式。

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

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

是的,编译器可以优化以删除初始化。该技术称为死商店优化。确定死亡商店是否发生是数据流分析的一部分。

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

这是因为在C 中,执行是按行行。因此,首先声明对象,并在声明后立即获得构造函数分配的值。之后A,B和C值更改。

to 优化,您可以将构造函数使用带有类似

的默认参数的构造函数
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
}