首页 > 解决方案 > 初始化类成员的任何开销?

问题描述

假设我有以下代码

class C {
public:
  explicit C() :
     member()
  {}
private:
  int member;
};

我想member()将我的变量值初始化member为零。

我的问题是:这在运行时是否有任何开销?还是在编译时以某种特定方式完成?

标签: c++

解决方案


简而言之:开销很小,但编译器很聪明!

长版:

内存必须清零,这需要一些工作。您可以看到,当您将类编译为程序集时,还有一个简单的驱动程序函数

int main() { C c; } 

使用-O1优化。

然后没有成员初始化,生成的代码看起来像

main: # @main
  push rax
  mov rdi, rsp
  call C::C() [base object constructor]
  xor eax, eax
  pop rcx
  ret
C::C() [base object constructor]: # @C::C() [base object constructor]
  ret

在最后两行中,您可以看到构造函数是微不足道的。当您使用括号添加成员初始化时,它变为

C::C() [base object constructor]: # @C::C() [base object constructor]
  mov qword ptr [rdi], 0
  ret

mov指令将DWORD某个特定内存位置的 a 设置为零。DWORD是 32 位的。

编译器可能能够组合初始化。例如,如果您添加第二个int

class C {
public:
  explicit C()
     : member(), anotherMember()     
  {}
private:
  int member;
  int anotherMember; // <====
};

int main() {
    C c;
}

然后DWORD更改为 aQWORD所以它实际上一次将两个整数归零。即使使用更高的优化级别,您也会看到这一点,例如,当您添加一些编译器无法优化的内容时,例如读取stdin编译它-O2

#include <iostream> 

class C {
public:
  explicit C()
     : member()
  {}
  int member;
};

int main() {
    int x;
    C c;
    std::cin >> c.member;
}

那么构造函数主体将被内联到主函数中,但您仍然会找到零指令

mov dword ptr [rsp], 0

另请注意,根据实例化后的代码,编译器可能会进一步优化。例如,如果您查看输出

C c;
c.member = expression;

然后你会看到零赋值将从输出中删除。


推荐阅读