0

We have different types of initializing class or struct member variable at c++ one of them is:

struct foo {
    foo() : a(true), b(true), c(true) {}
    bool a;
    bool b;
    bool c;
 } bar;

and another one is :

struct foo {
    bool a = true;
    bool b = true;
    bool c = true;
 } bar;

Is there differences between them ?

which one is better to use ?

1 Answers1

0

TL;DR Don't care about such trivialities unless you know you have to. And if you have to, you need to analyze concrete assembly.

In general from pure language perspective such questions do not make sense. For what it's worth, c++ compiler can cripple performance if it wished. Any program exhibiting the same behaviour is just as legal, and performance is not a visible effect.

Talking about performance makes sense only in concrete application that is concrete assembly using a particular compiler and configuration, especially optimizations.

Full study: I will be using clag 7.0.0 on godbolt compiler explorer

Your case is weird because it defines global values.For default optimization options:

  1. the c'tor was generated and object is stored as zeroes
  2. there was no code and the object was generate as 3 ones

So clearly option 2 seems better:

__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

However using -O1 reduces code to no difference:

bar:
        .byte   1                       # 0x1
        .byte   1                       # 0x1
        .byte   1                       # 0x1

bar2:
        .byte   1                       # 0x1
        .byte   1                       # 0x1
        .byte   1                       # 0x1

When using fooas type in a program ctor is generated for both cases -O0 and -O1 (same ctor for each case, different per optimization level). See: https://godbolt.org/z/0il6ou

And for -O2 the objects get dissolved.

luk32
  • 15,812
  • 38
  • 62