Topic: initialization of const non-PODs
Author: Rene van Oostrum <rene@cs.ust.hk>
Date: 2000/02/16 Raw View
I'm getting a head-ache from trying to read 8.5, paragraph 9. I
stumbled upon this paragraph after g++ surprised me by rejecting the
following code:
#include <string>
class A { };
class B {
public:
B() { }
};
class C {
A a;
};
class D {
B b;
};
class E {
std::string s;
};
int main(){
const A a;
const B b;
const C c;
const D d;
const E e;
return 0;
}
g++ gives error messages for the declarations of "const A a" and
"const C c" in main ('uninitialized constant'). Before reading 8.5 par
1, I thought that all five declarations were correct, since all
classes have a default constructor (compiler-declared/defined for
A,C,D,E, and user-declared/defined for B), and I figured that all
objects a-e would be initialized by the default constructors of their
respective classes. I figured wrong, I guess.
8.5 par 1 says:
"If no initializer is specified for an object, and the object is of
(possibly cv-qualified) non-POD class type (or array thereof), the
object shall be default-initialized; if the object is of
const-qualified type, the underlying class type shall have a
user-declared default constructor. Otherwise, if no initializer is
specified for an object, the object and its subobjects, if any, have
an indeterminate initial value 90) ; if the object or any of its
subobjects are of const-qualified type, the program is ill-formed."
If I'm correct, then only class A is a POD: B has a user-declared
default constructor, and C-E have private data members, so they are
not aggregates (8.5.1, par 1, quoted at end), and so they are not POD
classes (9, par 4, quoted at end).
Hence, only the declaration "const B b" is correct. "const A a" is
incorrect by the second sentence of 8.5, par 1 ("Otherwise..."); the
last three declarations are incorrect by the last part of the first
sentence ("if the object ... default constructor").
That last part of the first sentence of 8.5 par 1 really surprised
me. If I read this correctly, it means that compiler-declared (and
defined) default constructors are never used to initialize const
objects (of non-POD class type). I have never seen this in any text
book (including C++PL); I don't know of any compiler that rejects the
declarations of "const D d" and "const E e" in my code above (well, I
only tried three different compilers...). That doesn't say much, I
realize; text books nor compilers are authoritative.
However, 8.5 par 1 seems also inconsistent with 3.1 par 4 (again, if I
read all of this correctly). This paragraph says:
"[Note: in some circumstances, C++ implementations implicitly define
the default constructor (12.1), copy constructor (12.8), assignment
operator (12.8), or destructor (12.4) member functions. [Example:
given
struct C {
string s; // string is the standard library class (clause 21)
};
int main()
{
C a;
C b = a;
b = a;
}
the implementation will implicitly define functions to make the
definition of C equivalent to
struct C {
string s;
C(): s() { }
C(const C& x): s(x.s) { }
C& operator=(const C& x) { s = x.s; return *this; }
~C() { }
};
--end example] --end note]"
But: both versions of struct C are non-PODs (since they contain the
non-POD string member). By 8.5 par 1, I can't declare a "const C c"
for the first version of struct C, as this version does not have a
user-declared default constructor. The second version does have a
user-declared default constructor, so for this version, "const C c" is
legal. So the two versions are *not* equivalent according to 8.5 par
1.
I'm probably reading the standard incorrectly, and I would be grateful
if anyone could point out the flaws in my reasoning.
Thanks,
Rene
---
Relevant quotations from the standard:
8.5.1 par 1
"An aggregate is an array or a class (clause 9) with no user-declared
constructors (12.1), no private or protected non-static data members
(clause 11), no base classes (clause 10), and no virtual functions
(10.3)."
9, par 4
"A structure is a class defined with the class-key struct; its
members and base classes (clause 10) are public by default (clause
11). A union is a class defined with the class-key union; its members
are public by default and it holds only one data member at a time
(9.5). [Note: aggregates of class type are described in 8.5.1. ] A
POD-struct is an aggregate class that has no non-static data members
of type pointer to member, non-POD-struct, non-POD-union (or array of
such types) or reference, and has no user-defined copy assignment
operator and no user-defined destructor. Similarly, a POD-union is an
aggregate union that has no non-static data members of type pointer to
member, non-POD-struct, non-POD-union (or array of such types) or
reference, and has no user-defined copy assignment operator and no
user-defined destructor. A POD class is a class that is either a
POD-struct or a POD-union."
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 2000/02/16 Raw View
I agree with what you said. Only the const A a; line is correct.
I tried it with a couple of compilers and I got the same results you
did though. The compiler didn't catch the seemingly illegal definitions
of D and E. No doubt, the fact that the only datamembers present have
proper initializers seems to have thrown the compiler.
By the way, are you working from the draft? Your section numbers don't line up
with the text of the standard.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Rene van Oostrum <rene@cs.ust.hk>
Date: 2000/02/17 Raw View
I wrote:
class A { };
class B {
public:
B() { }
};
[ snip]
int main(){
const A a;
const B b;
[ snip ]
return 0;
}
Ron Natalie replied:
Ron> I agree with what you said. Only the const A a; line is
Ron> correct.
Actually, that's not what I said. :-) Only the "Const B b;" is
correct (if *I'm* correct).
Ron> By the way, are you working from the draft? Your section
Ron> numbers don't line up with the text of the standard.
Oops: I cutted/pasted the text from the PDF of the standard, but typed
the numbers manually. Please read all occurrences of "8.5 par 1" as
"8.5 par 9". (The fact that 8.5.1 par 1 was also involved got me
mixing up the numbers).
But more important: do you agree that 8.5 par 9 is inconsistent with
3.1 par 4? According to 8.5 par 9 it is legal to declare a "const C c"
for the second version of struct C in 3.1 par 4 (with a
user-declared/defined constructor), but it is not legal to declare a
"const C c" for the first version of struct C in 3.1 par 4 (without a
user-declared/defined constructor). So, the two versions are *not*
equivalent, as opposed to what 3.1 par 4 says.
Maybe I'm too picky about the word "equivalent". I read this as "it
doesn't make a difference whether the compiler defines and declares
these member functions, or whether the user does so." And that is not
correct.
The fact that all three compilers that I checked accepted the
declaration of a "const C c" for the first version of struct C in 3.1
par 4 may be an indication that I'm not the only one who was `mislead'
by this paragraph.
Rene van Oostrum
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]