* (e-mail address removed):
[snip quoted signature, please don't quote signatures]
I've been playing around with bits of code related to implicit
creation of default constructors and so far I've been able to relate
code behavior to the description in the standard except for the
following:
// struct S1 { int j; };
struct S1 { int j; S1 () {}; };
struct S2 { int i; S1 s1; };
int main()
{
S2 s2 = S2();
printf( "%d,%d\n", s2.i, s2.s1.j );
return 0;
}
There is no user-defined default constructor for S2 so an implicit
constructor is automatically declared by the compiler.
The first line of main creates an object with an initializer so the
compiler doesn't define that default constructor.
So the s2 struct is default-initialized but (since it has no defined
constructor) is zero-initialized.
The rules here are slightly different in C++98 (the original standard)
and C++03 (first technical corrigendum, the TC1).
C++03 introduced the notion of "valueinitialization" in order to tackle
just this problem, a correction of the C++98 semantics.
With C++98 semantics what happens is, as you state, a
default-initialization. And the problem with that is that the
definition of default-initialization, in §8.5./5, starts with "if T is a
non-POD class type, the default constructor for T is called". And in
the example above S2 is non-POD[1] (not a plain old C-like data type)
because it contains amemberof a type with a defined constructor, which
is not something possible in C, and so according to C++98 semantics you
just get a call of your do-nothing auto-created default constructor.
With C++03 semantics what happens is a valueinitialization, intended to
correct this problem. The wording of valueinitializationstarts with
"if T is a class type with a user-declared constructor, then the default
constructor for T is called". This doesn't apply to S2, which doesn't
have a user-declared constructor. But the next alternative, "if T is a
non-union class type without a user-declared constructor, then every
non-static datamemberand base-class component of T is
value-initialized", applies, recursively for S2::i and S2::s1. And for
S2::i the last alternative of this list applies, zero-initializion, and
for S2::s1 the first alternative applies, default constructor called.
So essentialy the compiler or compilers you have tested with evidently
implemented C++98 semantics, or perhaps just incorrectinitialization,
not C++03 semantics. One remedy is to upgrade the compiler(s). Another
more general solution is to simply define a default constructor.
Cheers, & hth.,
- Alf
Notes:
[1] Technically it is an "aggregate" type.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?