This is copy paste from this topic Initializing fields in constructor - initializer list vs constructor body
The author explains the following equivalence:
public : Thing(int _foo, int _bar){
member1 = _foo;
member2 = _bar;
}
is equivalent to
public : Thing(int _foo, int _bar) : member1(), member2(){
member1 = _foo;
member2 = _bar;
}
My understanding was that
- snippet 1 is a case of default-initialization (because of the absence of an initializer list)
- snippet 2 is a case of value-initialization (empty pairs of parentheses).
How are these two equivalent?
Your understanding is correct (assuming member1
and member2
have type `int). The two forms are not equivalent; in the
first, the members are not initialized at all, and cannot be
used until they have been assigned. In the second case, the
members will be initialized to 0. The two formulations are only
equivalent if the members are class types with user defined
constructors.
You are right but the author is kind of right too!
Your interpretation is completely correct as are the answers given by others. In summary the two snippets are equivalent if member1
and member2
are non-POD types.
For certain POD types they are also equivalent in some sense. Well, let's simplify a little more and assume member1
and member2
have type int
. Then, under the as-if-rule the complier is allowed to replace the second snippet with the first one. Indeed, in the second snippet the fact that member1
is first initlialized to 0
is not observable. Only its assignment to _foo
is. This is the same reasoning that allows the compiler to replace these two lines
int x = 0;
x = 1;
with this one
int x = 1;
For instance, I've compiled this code
struct Thing {
int member1, member2;
__attribute__ ((noinline)) Thing(int _foo, int _bar)
: member1(), member2() // initialization line
{
member1 = _foo;
member2 = _bar;
}
};
Thing dummy(255, 256);
with GCC 4.8.1 using option -O1
. (The __atribute((noinline))__
prevents the compiler from inlining the function). Then the generated assembly code is the same regardless whether the initialization line is present or not:
-O1
with or without initialization
0: 8b 44 24 04 mov 0x4(%esp),%eax
4: 89 01 mov %eax,(%ecx)
6: 8b 44 24 08 mov 0x8(%esp),%eax
a: 89 41 04 mov %eax,0x4(%ecx)
d: c2 08 00 ret $0x8
On the other hand, when compiled with -O0
the assembly code is different depending on whether the initialization line is present or not:
-O0
without initialization
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 89 4d fc mov %ecx,-0x4(%ebp)
9: 8b 45 fc mov -0x4(%ebp),%eax
c: 8b 55 08 mov 0x8(%ebp),%edx
f: 89 10 mov %edx,(%eax)
11: 8b 45 fc mov -0x4(%ebp),%eax
14: 8b 55 0c mov 0xc(%ebp),%edx
17: 89 50 04 mov %edx,0x4(%eax)
1a: c9 leave
1b: c2 08 00 ret $0x8
1e: 90 nop
1f: 90 nop
-O0
with initialization
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 04 sub $0x4,%esp
6: 89 4d fc mov %ecx,-0x4(%ebp)
9: 8b 45 fc mov -0x4(%ebp),%eax ; extra line #1
c: c7 00 00 00 00 00 movl $0x0,(%eax) ; extra line #2
12: 8b 45 fc mov -0x4(%ebp),%eax ; extra line #3
15: c7 40 04 00 00 00 00 movl $0x0,0x4(%eax) ; extra line #4
1c: 8b 45 fc mov -0x4(%ebp),%eax
1f: 8b 55 08 mov 0x8(%ebp),%edx
22: 89 10 mov %edx,(%eax)
24: 8b 45 fc mov -0x4(%ebp),%eax
27: 8b 55 0c mov 0xc(%ebp),%edx
2a: 89 50 04 mov %edx,0x4(%eax)
2d: c9 leave
2e: c2 08 00 ret $0x8
31: 90 nop
32: 90 nop
33: 90 nop
Notice that -O0
with initialization has four extra lines (marked above) than -O0
without initialization. These extra lines initialize the two members to zero.