@brief
when I learning java by , I see “The order of initialization is statics first…”. so… what about c++?
当我通过 thinking in java 学 java 时, 我注意到书中的一句话 “The order of initialization is statics first”. 那么, c++ 中是怎样对待的呢?
static think this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class A {public : int i2 = 1 ; static int i; A() { cout << "hello" << endl ; } }; int A::i = 10 ;void f () { A a; cout << A::i << endl ; A::i = 100 ; } int main () { A a; cout << A::i << endl ; thread t1 (f) ; thread t2 (f) ; t1.join(); t2.join(); }
class A has a static field i, it’s an integer with default value 10.
how did these codes do?
类 A 有一个静态字段 i, 这是一个具有默认值为10的整型字段
assembly time
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 _ZN1A1iE: ▹ .long▹ 10 ▹ .text ▹ .globl▹ _Z1fv ▹ .type▹ _Z1fv, @function _Z1fv: .LFB3324: ▹ .cfi_startproc ▹ pushq▹ %rbp ▹ .cfi_def_cfa_offset 16 ▹ .cfi_offset 6, -16 ▹ movq▹ %rsp, %rbp ▹ .cfi_def_cfa_register 6 ▹ subq▹ $16, %rsp ▹ leaq▹ -4(%rbp), %rax ▹ movq▹ %rax, %rdi ▹ call▹ _ZN1AC1Ev ▹ movl▹ _ZN1A1iE(%rip), %eax // _ZN1A1iE ▹ movl▹ %eax, %esi ▹ leaq▹ _ZSt4cout(%rip), %rdi ▹ call▹ _ZNSolsEi@PLT ▹ movq▹ %rax, %rdx ▹ movq▹ _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax ▹ movq▹ %rax, %rsi ▹ movq▹ %rdx, %rdi ▹ call▹ _ZNSolsEPFRSoS_E@PLT ▹ movl▹ $100, _ZN1A1iE(%rip) ▹ nop ▹ leave ▹ .cfi_def_cfa 7, 8 ▹ ret ... main: .LFB3325: ▹ .cfi_startproc ▹ .cfi_personality 0x9b,DW.ref.__gxx_personality_v0 ▹ .cfi_lsda 0x1b,.LLSDA3325 ▹ pushq▹ %rbp ▹ .cfi_def_cfa_offset 16 ▹ .cfi_offset 6, -16 ▹ movq▹ %rsp, %rbp ▹ .cfi_def_cfa_register 6 ▹ pushq▹ %rbx ▹ subq▹ $40, %rsp ▹ .cfi_offset 3, -24 ▹ leaq▹ -20(%rbp), %rax ▹ movq▹ %rax, %rdi .LEHB0: ▹ call▹ _ZN1AC1Ev ▹ movl▹ _ZN1A1iE(%rip), %eax // _ZN1A1iE ▹ movl▹ %eax, %esi ▹ leaq▹ _ZSt4cout(%rip), %rdi ▹ call▹ _ZNSolsEi@PLT ▹ movq▹ %rax, %rdx ▹ movq▹ _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax ▹ movq▹ %rax, %rsi ▹ movq▹ %rdx, %rdi ▹ call▹ _ZNSolsEPFRSoS_E@PLT ▹ leaq▹ -32(%rbp), %rax ▹ leaq▹ _Z1fv(%rip), %rsi ▹ movq▹ %rax, %rdi ▹ call▹ _ZNSt6threadC1IRFvvEJEEEOT_DpOT0_
so, static value initialize while process run then copy to register while class construct function executed
所以, 静态变量随着程序运行而初始化, 随后在类构造函数完成后, 将其值拷贝到寄存器
this can also be discovered in gdb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 (gdb) b main Breakpoint 1 at 0x1908: file t.cpp, line 33. (gdb) c The program is not being run. (gdb) r Starting program: /root/cpp/a.out [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main () at t.cpp:33 33 A a; (gdb) p A::i $2 = 10 (gdb) p &A::i $3 = (int *) 0x555555758100 <A::i> (gdb) p (int)0x555555758100 $4 = 1433764096 (gdb) p {int}0x555555758100 $5 = 10
how about static const? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class A{ public: int i2 = 1; static int const i = 11; A() { cout << "hello" << endl; } }; ... _Z1fv: .LFB3324: ▹ .cfi_startproc ▹ pushq▹ %rbp ▹ .cfi_def_cfa_offset 16 ▹ .cfi_offset 6, -16 ▹ movq▹ %rsp, %rbp ▹ .cfi_def_cfa_register 6 ▹ subq▹ $16, %rsp ▹ leaq▹ -4(%rbp), %rax ▹ movq▹ %rax, %rdi ▹ call▹ _ZN1AC1Ev ▹ movl▹ $11, %esi // * ▹ leaq▹ _ZSt4cout(%rip), %rdi ... main: .LFB3325: ▹ .cfi_startproc ▹ .cfi_personality 0x9b,DW.ref.__gxx_personality_v0 ▹ .cfi_lsda 0x1b,.LLSDA3325 ▹ pushq▹ %rbp ▹ .cfi_def_cfa_offset 16 ▹ .cfi_offset 6, -16 ▹ movq▹ %rsp, %rbp ▹ .cfi_def_cfa_register 6 ▹ pushq▹ %rbx ▹ subq▹ $40, %rsp ▹ .cfi_offset 3, -24 ▹ leaq▹ -20(%rbp), %rax ▹ movq▹ %rax, %rdi .LEHB0: ▹ call▹ _ZN1AC1Ev ▹ movl▹ $11, %esi // * ▹ leaq▹ _ZSt4cout(%rip), %rdi
if you use static const, there no space to store value, just a compile-time const value
如果使用static const, 则不会有空间存储值, 则是一个编译时常量