不同 class 或结构初始化方法之间的性能差异是什么?
What is performance difference between different class or struct initialization methods?
我们在 C++ 中有不同类型的初始化 class 或结构成员变量
其中之一是:
struct foo {
foo() : a(true), b(true), c(true) {}
bool a;
bool b;
bool c;
} bar;
另一个是:
struct foo {
bool a = true;
bool b = true;
bool c = true;
} bar;
它们之间有区别吗?
哪个更好用?
TL;DR 除非你知道你必须关心,否则不要关心这些琐事。如果必须,则需要分析具体装配。
总的来说,从纯语言的角度来看,这样的问题是没有意义的。对于它的价值,c++ 编译器可以根据需要削弱性能。任何表现出相同行为的程序都是合法的,性能不是可见的效果。
只有在使用特定编译器和配置(尤其是优化)的具体程序集的具体应用程序中谈论性能才有意义。
全部学习:
我将在 godbolt compiler explorer
上使用 clag 7.0.0
你的情况很奇怪,因为它定义了全局 values.For 默认优化选项:
- c'tor 已生成且对象存储为零
- 没有代码,对象生成为 3 个
显然选项 2 似乎更好:
__cxx_global_var_init: # @__cxx_global_var_init
push rbp
mov rbp, rsp
movabs rdi, offset bar
call foo::foo() [base object constructor]
pop rbp
ret
foo::foo() [base object constructor]: # @foo::foo() [base object constructor]
push rbp
mov rbp, rsp
mov qword ptr [rbp - 8], rdi
mov rdi, qword ptr [rbp - 8]
mov byte ptr [rdi], 1
mov byte ptr [rdi + 1], 1
mov byte ptr [rdi + 2], 1
pop rbp
ret
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
push rbp
mov rbp, rsp
call __cxx_global_var_init
pop rbp
ret
bar:
.zero 3
bar2:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
但是使用 -O1
将代码减少到没有区别:
bar:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
bar2:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
当在程序中使用 foo
as 类型时,会为 -O0
和 -O1
两种情况生成程序构造函数(每种情况都使用相同的构造函数,每个优化级别不同)。参见:https://godbolt.org/z/0il6ou
而对于 -O2
物体溶解了。
我们在 C++ 中有不同类型的初始化 class 或结构成员变量 其中之一是:
struct foo {
foo() : a(true), b(true), c(true) {}
bool a;
bool b;
bool c;
} bar;
另一个是:
struct foo {
bool a = true;
bool b = true;
bool c = true;
} bar;
它们之间有区别吗?
哪个更好用?
TL;DR 除非你知道你必须关心,否则不要关心这些琐事。如果必须,则需要分析具体装配。
总的来说,从纯语言的角度来看,这样的问题是没有意义的。对于它的价值,c++ 编译器可以根据需要削弱性能。任何表现出相同行为的程序都是合法的,性能不是可见的效果。
只有在使用特定编译器和配置(尤其是优化)的具体程序集的具体应用程序中谈论性能才有意义。
全部学习: 我将在 godbolt compiler explorer
上使用 clag 7.0.0你的情况很奇怪,因为它定义了全局 values.For 默认优化选项:
- c'tor 已生成且对象存储为零
- 没有代码,对象生成为 3 个
显然选项 2 似乎更好:
__cxx_global_var_init: # @__cxx_global_var_init
push rbp
mov rbp, rsp
movabs rdi, offset bar
call foo::foo() [base object constructor]
pop rbp
ret
foo::foo() [base object constructor]: # @foo::foo() [base object constructor]
push rbp
mov rbp, rsp
mov qword ptr [rbp - 8], rdi
mov rdi, qword ptr [rbp - 8]
mov byte ptr [rdi], 1
mov byte ptr [rdi + 1], 1
mov byte ptr [rdi + 2], 1
pop rbp
ret
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
push rbp
mov rbp, rsp
call __cxx_global_var_init
pop rbp
ret
bar:
.zero 3
bar2:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
但是使用 -O1
将代码减少到没有区别:
bar:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
bar2:
.byte 1 # 0x1
.byte 1 # 0x1
.byte 1 # 0x1
当在程序中使用 foo
as 类型时,会为 -O0
和 -O1
两种情况生成程序构造函数(每种情况都使用相同的构造函数,每个优化级别不同)。参见:https://godbolt.org/z/0il6ou
而对于 -O2
物体溶解了。