I'm running into a problem with the aggregate initialization provided
by MSVC compiler. I have several structures that contain pointers to
dynamically allocated data, in the example below a vector of ints.
BTW: I realize this data should be hidden in a class and only accessed
through accessors, but this is the reality I'm faced with today.
There are several places in the code where these structures are
cleared with memset and resued. The problem is that memset is
clearing the pointers to the dynamically allocated memory and whamo
I'm leaking. Instead of using memset I'd like to force member-wise
assignment with an emptied version of the structure being cleared.
So here's what I'm doing:
#include <vector>
using namespace std;
struct POD
{
int nNum;
vector<int> data;
};
int main()
{
POD good_pod1 = {0}; // Create an empty POD
POD good_pod2;
good_pod2.data.push_back(5);
good_pod2 = good_pod1; // vector<int>::operator=() frees mem
}
However, if the POD members are reordered I get a type mismatch
compiler errror.
// Using this POD structure in the code above will not compile
struct POD
{
int nNum;
vector<int> data;
};
So my question is what's going on here? I thought that if you
provided fewer initializers than members the compiler would use the
last initializer to initialize the remaining data members. If my
understanding is correct then in the first case good_pod2 is
initialized with 0 (i.e. int(0) and vector<int>(0) are called). In
the second case, when data is declared before nNum in the POD
structure, why do I get a compiler error making what appears to be the
same calls - vector<int>(0) and int(0)?
Any direction would be much appreciated.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
mcarruth
|
11/26/2003 7:50:30 PM |
|
On 26 Nov 2003 14:50:30 -0500, mcarruth@email.com (Michael Carruth)
wrote:
> struct POD
> {
> int nNum;
> vector<int> data;
> };
> int main()
> {
> POD good_pod1 = {0}; // Create an empty POD
The missing initializer is a properly cast 0. You get:
POD good_pod1 = { 0, vector<int>(0) };
> POD good_pod2;
> good_pod2.data.push_back(5);
> good_pod2 = good_pod1; // vector<int>::operator=() frees mem
> }
> However, if the POD members are reordered I get a type mismatch
> compiler errror.
Reversing the members gives a type mismatch because you are supplying
an int where a vector is required. The constructor in question is
explicit.
struct POD
{
vector<int> data;
int nNum;
};
POD good_pod1 = { vector<int>(0) };
No error now.
You should also know that good_pod2 has an uninitialized int not a
zero. The compiler generated default ctor does nothing for the
int but calls the vector default ctor.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
11/27/2003 9:31:52 AM
|
|
mcarruth@email.com (Michael Carruth) wrote in message news:<8083a32d.0311260821.37bd9b4c@posting.google.com>...
> So my question is what's going on here? I thought that if you
> provided fewer initializers than members the compiler would use the
> last initializer to initialize the remaining data members.
No, it just uses default initialization for the rest of data members.
regards,
radu
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
radugrigore
|
11/28/2003 8:58:36 AM
|
|
John Potter <jpotter@falcon.lhup.edu> wrote in message
news:<vl5asvkfmqfvrdpom0k2mcbh9pob78uoag@4ax.com>...
> On 26 Nov 2003 14:50:30 -0500, mcarruth@email.com (Michael Carruth)
> wrote:
> > struct POD
> > {
> > int nNum;
> > vector<int> data;
> > };
> > int main()
> > {
> > POD good_pod1 = {0}; // Create an empty POD
> The missing initializer is a properly cast 0. You get:
> POD good_pod1 = { 0, vector<int>(0) };
That's not how I read the standard. �8.5.1/7: "If there are fewer
initializers in the list than there are members in the aggregate, then
each member not explicitly initialized shall be default-initialized" and
�8.5/6: "To default-initialize an object of type T means: -- if T is a
non-POD class type [the case of vector<int>], the default constructor
for T is called." So the equivalent is:
POD good_pod1 = { 0, vector<int>() } ;
There is NO conversion of a zero.
> > POD good_pod2;
> > good_pod2.data.push_back(5);
> > good_pod2 = good_pod1; // vector<int>::operator=() frees mem
> > }
> > However, if the POD members are reordered I get a type mismatch
> > compiler errror.
> Reversing the members gives a type mismatch because you are supplying
> an int where a vector is required. The constructor in question is
> explicit.
> struct POD
> {
> vector<int> data;
> int nNum;
> };
> POD good_pod1 = { vector<int>(0) };
> No error now.
> You should also know that good_pod2 has an uninitialized int not a
> zero.
I hope not. This would be a gratuious incompatibility with C -- an
incredible one, in which C++ was being less safe, and invoking less
behind the scenes magic than C. However, as we've just seen, C++ uses
"default initialization" in this case, and we again have �8.5/6: "[...]
-- otherwise, the storage for the object is zero-initialized." In sum,
if T is not a non-POD class type (or an array of non-POD class types),
we follow the same rules as C.
> The compiler generated default ctor does nothing for the int but calls
> the vector default ctor.
By "compiler generated default constructor" for int, you mean int(),
right? Like in the example in �8.5./1/7.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
11/28/2003 5:03:08 PM
|
|
On 28 Nov 2003 12:03:08 -0500, kanze@gabi-soft.fr wrote:
> John Potter <jpotter@falcon.lhup.edu> wrote in message
> news:<vl5asvkfmqfvrdpom0k2mcbh9pob78uoag@4ax.com>...
> > On 26 Nov 2003 14:50:30 -0500, mcarruth@email.com (Michael Carruth)
> > wrote:
> > > struct POD
> > > {
> > > int nNum;
> > > vector<int> data;
> > > };
> > > int main()
> > > {
> > > POD good_pod1 = {0}; // Create an empty POD
> > The missing initializer is a properly cast 0. You get:
> > POD good_pod1 = { 0, vector<int>(0) };
> That's not how I read the standard. �8.5.1/7: "If there are fewer
> initializers in the list than there are members in the aggregate, then
> each member not explicitly initialized shall be default-initialized" and
> �8.5/6: "To default-initialize an object of type T means: -- if T is a
> non-POD class type [the case of vector<int>], the default constructor
> for T is called." So the equivalent is:
> POD good_pod1 = { 0, vector<int>() } ;
> There is NO conversion of a zero.
Yes, thank you.
> > > POD good_pod2;
Note lack of initializer.
> > You should also know that good_pod2 has an uninitialized int not a
> > zero.
> I hope not. This would be a gratuious incompatibility with C -- an
> incredible one, in which C++ was being less safe, and invoking less
> behind the scenes magic than C. However, as we've just seen, C++ uses
> "default initialization" in this case, and we again have �8.5/6: "[...]
> -- otherwise, the storage for the object is zero-initialized." In sum,
> if T is not a non-POD class type (or an array of non-POD class types),
> we follow the same rules as C.
Did you miss the above where good_pod2 has no initializer?
> > The compiler generated default ctor does nothing for the int but calls
> > the vector default ctor.
> By "compiler generated default constructor" for int, you mean int(),
> right? Like in the example in �8.5./1/7.
I'm talking about the compiler generated default constructor for POD
POD () : data() { }
It does not initialize nNum.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
11/29/2003 10:45:04 AM
|
|
On 28 Nov 2003 12:03:08 -0500, kanze@gabi-soft.fr wrote:
>John Potter <jpotter@falcon.lhup.edu> wrote in message
>news:<vl5asvkfmqfvrdpom0k2mcbh9pob78uoag@4ax.com>...
> > On 26 Nov 2003 14:50:30 -0500, mcarruth@email.com (Michael Carruth)
> > wrote:
>
[snip]
>
> > > POD good_pod2;
> > > good_pod2.data.push_back(5);
> > > good_pod2 = good_pod1; // vector<int>::operator=() frees mem
> > > }
>
> > > However, if the POD members are reordered I get a type mismatch
> > > compiler errror.
>
> > Reversing the members gives a type mismatch because you are supplying
> > an int where a vector is required. The constructor in question is
> > explicit.
>
> > struct POD
> > {
> > vector<int> data;
> > int nNum;
> > };
>
> > POD good_pod1 = { vector<int>(0) };
>
> > No error now.
>
> > You should also know that good_pod2 has an uninitialized int not a
> > zero.
>
>I hope not. This would be a gratuious incompatibility with C -- an
>incredible one, in which C++ was being less safe, and invoking less
>behind the scenes magic than C. However, as we've just seen, C++ uses
>"default initialization" in this case, and we again have �8.5/6: "[...]
>-- otherwise, the storage for the object is zero-initialized." In sum,
>if T is not a non-POD class type (or an array of non-POD class types),
>we follow the same rules as C.
>
> > The compiler generated default ctor does nothing for the int but calls
> > the vector default ctor.
>
>By "compiler generated default constructor" for int, you mean int(),
>right? Like in the example in �8.5./1/7.
struct POD
{
int nNum;
vector<int> data;
};
This is not a POD - it is a non POD without a constructor, which is a
special case affected by TC1 which defined a new term called value
initialization expressly for non PODs without constructors.
[ To Michael ] - you cannot use memset on a non POD - it produces
undefined behaviour, such as the memory leak you observed. You're
(un)lucky not to get a crash.
int main()
{
POD good_pod1 = {0}; // Create an empty POD
POD good_pod2;
good_pod2.data.push_back(5);
good_pod2 = good_pod1; // vector<int>::operator=() frees mem
}
good_pod2 has no initialiser here. In both 1998 C++ and 2003 C++ std,
default initialisation occurs. The meaning of default initialisation
did not change with TC1 and for non PODs, the default constructor is
called. 12.1 para 7 and 12.6.2 para 4 mean the implicit default
constructor results in non POD members and bases being default
initialised and POD members left uninitialised. Hence the vector member
is default constructed and the int member is uninitialised.
However, if you do this
POD good_pod2 = POD();
( note you can't do POD good_pod2(); because this declares a function as
pointed out in 8.5 para 1)
the construct POD() produces value initialisation according to the 2003
std, which results in all members and sub members being either default
constructed or zero initialised - hence the int member will be set to
zero in this case. According to the 1998 std, the construct POD()
produced default initialisation - TC1 changed 8.5 para 7 and 5.2.3 para
2 (and other places) to use value initialisation.
Value initialisation effectively means that all "parts" of the object
have a well defined value - except for sub members of a class type
that has an explicit default constructor which leaves some members or
bases uninitialised - of these, non POD members/bases are default
initialiased and POD members/bases are uninitialised
The value initialisation defined by TC1 affects STL containers that use
T() as a default argument - this includes the vector default
constructor.
A common confusion is the term default construction of POD built in
types - there is no such thing as default construction of built in
types, despite Josuttis and Stroustrup saying otherwise. For a built in
type such as int, the construct int() (e.g. as used in the default
argument for vector), results in value initialisation (TC1) or default
initialisation (1998 std). Nowhere does the C++ std define the meaning
of default construction for built in types.
TC1 also applies value initialisation to aggregates (instead of default
initialisation) - i.e. when there are fewer initialisers in the list,
remaining members are value initialised. This makes no difference to
the case above because in both cases (1998 and 2003 std), the int member
is set to zero when you do
struct nonPOD
{
vector<int> data;
int num;
};
nonPOD good_nonPOD = {};
because default initialisation of all POD types, produces zero
initialisation.
The defect report relating to value initialisation was around 1999 so
there's probably several compilers that support it now.
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Graeme
|
11/29/2003 10:51:05 AM
|
|
In article <8083a32d.0311260821.37bd9b4c@posting.google.com>, Michael
Carruth <mcarruth@email.com> writes
>So my question is what's going on here? I thought that if you
>provided fewer initializers than members the compiler would use the
>last initializer to initialize the remaining data members. If my
>understanding is correct then in the first case good_pod2 is
>initialized with 0 (i.e. int(0) and vector<int>(0) are called). In
>the second case, when data is declared before nNum in the POD
>structure, why do I get a compiler error making what appears to be the
>same calls - vector<int>(0) and int(0)?
I believe that your understanding is wrong. Any uninitialised items are
default intialised which is equivalent to zero initialisation in the
case of fundamental types)
Try compiling:
#include <vector>
int main(){
std::vector<int> v = 0;
}
and examine the error messages and you will get the same ones as in
your first example (there is a copying error in your second case). Note
that this is one of the cases where using functional style
initialisation gives different results so:
std::vector<int>(0);
is OK.
The reason that your first version works is that in:
POD good_pod1 = {0};
the provided '0' is used to initialise the nNum member and the data
member is then default constructed.
--
Francis Glassborow ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
11/29/2003 4:31:10 PM
|
|
In article <vl5asvkfmqfvrdpom0k2mcbh9pob78uoag@4ax.com>, John Potter
<jpotter@falcon.lhup.edu> writes
>On 26 Nov 2003 14:50:30 -0500, mcarruth@email.com (Michael Carruth)
>wrote:
>
> > struct POD
> > {
> > int nNum;
> > vector<int> data;
> > };
>
> > int main()
> > {
> > POD good_pod1 = {0}; // Create an empty POD
>
>The missing initializer is a properly cast 0. You get:
>
> POD good_pod1 = { 0, vector<int>(0) };
I think you are mistaken. 8.5.1/7 requires that the extras be
value-initialised. 8.5 para 5 bullet 9 says:
if T is a class type with a user-declared constructor, then the default
ctor for T is called (and the initialisation is ill-formed if T has no
accessible default ctor). I think that means that the above line should
be replaced with:
POD good_pod1 = {0, vector<int>() };
In this case it makes no difference but in the general case it does.
--
Francis Glassborow ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Francis
|
11/29/2003 4:31:46 PM
|
|
John Potter wrote:
> You should also know that good_pod2 has an uninitialized int not a
> zero. The compiler generated default ctor does nothing for the
> int but calls the vector default ctor.
Not as far as I know. Once you give an initializer for a POD the rest of
the elements are zero initialized. IIRC. But I am not at all sure that
something with a vector in it is POD. Since vector has a constructor,
therefore the struct has one as well...
--
WW aka Attila
:::
"Captain, could I play some jazz?"
"Make it soul, No. 1"
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
White
|
11/29/2003 4:37:51 PM
|
|
John Potter <jpotter@falcon.lhup.edu> writes:
[...]
| > By "compiler generated default constructor" for int, you mean int(),
| > right? Like in the example in �8.5./1/7.
|
| I'm talking about the compiler generated default constructor for POD
|
| POD () : data() { }
|
| It does not initialize nNum.
And it you say POD(), then the nNum member is (value-)initialized.
--
Gabriel Dos Reis
gdr@integrable-solutions.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Gabriel
|
11/29/2003 7:27:30 PM
|
|
On 29 Nov 2003 11:37:51 -0500, "White Wolf" <wolof@freemail.hu> wrote:
> John Potter wrote:
> > You should also know that good_pod2 has an uninitialized int not a
> > zero. The compiler generated default ctor does nothing for the
> > int but calls the vector default ctor.
> Not as far as I know.
You missed that good_pod2 has no initializer. Only good_pod1 had one.
> Once you give an initializer for a POD the rest of
> the elements are zero initialized. IIRC.
We both got this wrong. They are default initialized.
> But I am not at all sure that something with a vector in it is POD.
It is not, but it is still an aggregate and may be brace initialized.
> Since vector has a constructor, therefore the struct has one as well...
All structs including POD structs have compiler generated things. One
point worth repeating is the difference between no initializer and
default initialization.
struct S { int x; };
void f () {
S s1; // s1.x is uninitialized
S s2 = S(); // s2.x is zero
}
The term default constructed seems to have lost meaning. The first is
uninitialized like new S and the second is value initialized like new
S().
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
11/29/2003 7:45:34 PM
|
|
John Potter wrote:
> On 29 Nov 2003 11:37:51 -0500, "White Wolf" <wolof@freemail.hu> wrote:
>
>> John Potter wrote:
>>> You should also know that good_pod2 has an uninitialized int not a
>>> zero. The compiler generated default ctor does nothing for the
>>> int but calls the vector default ctor.
>
>> Not as far as I know.
>
> You missed that good_pod2 has no initializer. Only good_pod1 had one.
Oopps. :-)
>> Once you give an initializer for a POD the rest of
>> the elements are zero initialized. IIRC.
>
> We both got this wrong. They are default initialized.
Not as far as I understood. I was reading the corresponding part of the
standard due to another recent thread about the topic. Of course I might
have misunderstood something.
In 8.5.1 para 8 Simon says:
If there are fewer /initializers/ in the list than there are members in the
aggregate, then each member not explicitly initialized shall be
/default-initialized/ (8.5).
In 8.5 para 5 one can read Simon saying:
To /default-initialize/ an object of type T means:
— if T is a nonPOD class type (clause 9), the default constructor for T is
called (and the initialization is ill-formed if T has no accessible default
constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the storage for the object is zero-initialized.
Now all I meant for POD types is that they are zero-initialized. And IIRC
in this POD2 (really non-POD) the second element was an integer, a POD. So
what I meant is that if we initialize the vector in the initializer but give
nothing for the int to eat, the int will be zero initialized. I should have
been clearer - for sure.
>> But I am not at all sure that something with a vector in it is POD.
>
> It is not, but it is still an aggregate and may be brace initialized.
Yeah, I did recall it incorrectly. In 8.5.1 para 1 we can read:
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).
As for the meaning of user-declared constructors in 12.1 - I could not find
their definition. The term user-defined is not found in there by my Acrobat
reader. But it is clear that I have mixed this requirement up with the
trivial constructor.
>> Since vector has a constructor, therefore the struct has one as
>> well...
>
> All structs including POD structs have compiler generated things.
As what? IIRC if it is really a POD is has nothing generated, since the
generated stuff is all no-op.
> One
> point worth repeating is the difference between no initializer and
> default initialization.
Certainly.
> struct S { int x; };
> void f () {
> S s1; // s1.x is uninitialized
> S s2 = S(); // s2.x is zero
> }
>
> The term default constructed seems to have lost meaning. The first is
> uninitialized like new S and the second is value initialized like new
> S().
I believe that our case was a bit different:
struct S { int x; int y; };
void f () {
S s1; // s1.x and s1.y is uninitialized
S s2 = { 1 }; // s2.x is one, s1.y is zero
}
--
WW aka Attila
:::
You say tomato, I say ketchup.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
White
|
11/30/2003 10:19:05 AM
|
|
On 29 Nov 2003 14:45:34 -0500, John Potter <jpotter@falcon.lhup.edu>
wrote:
>You missed that good_pod2 has no initializer. Only good_pod1 had one.
>
>> Once you give an initializer for a POD the rest of
>> the elements are zero initialized. IIRC.
You don't even have to give *one* initialiser. If you use empty braces,
all elements are value initialized
>
>We both got this wrong. They are default initialized.
In the 1998 std they are default initialized but in 2003 std, it's value
initialization which makes a difference to any element which has type
"non POD without a constructor".
>
>> But I am not at all sure that something with a vector in it is POD.
>
>It is not, but it is still an aggregate and may be brace initialized.
Yes, and each member of the aggregate for which an initializer is
explicitly provided in the brace enclosed list is copy initialised
(12.6.1 para 2). 8.5 para 12 says copy init. is equivalent to
T x = a; - and para 14 effectively says if T is a class type then
either a copy constructor or user defined conversion sequence that can
convert "a" into type T is required. For the user defined conversion
sequence, an accessible copy constructor is still required but can be
elided.
>
>> Since vector has a constructor, therefore the struct has one as well...
>
>All structs including POD structs have compiler generated things. One
>point worth repeating is the difference between no initializer and
>default initialization.
yes, except that if there's no initializer, then default initialization
occurs, and if there is an initilizer then there's a bunch of rules that
apply which I partially listed above when describing T x = a;
>
>struct S { int x; };
>void f () {
> S s1; // s1.x is uninitialized
> S s2 = S(); // s2.x is zero
> }
>
>The term default constructed seems to have lost meaning.
No it hasn't, but people often make up their own interpretation of what
default construction applied to built in types means because the C++
standard doesn't define it and Stroustrup and Josuttis claim that it
means T() which is described in 5.2.3 para 2 as being value
initialisation which is "zero converted to type T" for built in types.
> The first is
>uninitialized like new S
The first is default initialized, which for non PODs means the default
constructor is called and for PODs like S, s1 is uninitialised.
> and the second is value initialized like new
>S().
Correct, and after the creation of a temporary "value initialised" S
object, the copy constructor may or may not be called to copy it into
s2.
I should have said in my earlier post, the reason for the new term
"value initialisation" is so that for T(), if T is a non POD without a
constructor, the POD members of T are effectively zero initialised and
members which are "non POD without a constructor" are value initialised
- which results in kind of "recursive value initialisation".
In the 1998 std, T() is default initialisation, which for non PODs means
default construction, - which for non PODs with no constructor, leaves
POD members uninitialised. In the 2003 std, T() is value
initialization.
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Graeme
|
11/30/2003 10:32:18 AM
|
|
On 29 Nov 2003 14:45:34 -0500, John Potter <jpotter@falcon.lhup.edu>
wrote:
>
>All structs including POD structs have compiler generated things. One
>point worth repeating is the difference between no initializer and
>default initialization.
>
>struct S { int x; };
>void f () {
> S s1; // s1.x is uninitialized
> S s2 = S(); // s2.x is zero
> }
>
>The term default constructed seems to have lost meaning. The first is
>uninitialized like new S and the second is value initialized like new
>S().
I replied to this already where I mistakenly said that the first is
default initialised, thinking of S being a non POD, however, you are
correct, the first (s1) is uninitialised because S is a POD. If S is a
non POD, then default initialisation of s1 occurs. My apologies for the
confusion.
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Graeme
|
11/30/2003 10:33:45 AM
|
|
On 30 Nov 2003 05:33:45 -0500, Graeme Prentice <deepblue57x@yahoo.co.nz>
wrote:
> On 29 Nov 2003 14:45:34 -0500, John Potter <jpotter@falcon.lhup.edu>
> wrote:
> >All structs including POD structs have compiler generated things. One
> >point worth repeating is the difference between no initializer and
> >default initialization.
> >struct S { int x; };
> >void f () {
> > S s1; // s1.x is uninitialized
> > S s2 = S(); // s2.x is zero
> > }
> >The term default constructed seems to have lost meaning. The first is
> >uninitialized like new S and the second is value initialized like new
> >S().
> I replied to this already where I mistakenly said that the first is
> default initialised, thinking of S being a non POD, however, you are
> correct, the first (s1) is uninitialised because S is a POD. If S is a
> non POD, then default initialisation of s1 occurs. My apologies for the
> confusion.
You just added more confusion. In the first, s1 is default initialized
because it is a class type. Because there is no user defined default
ctor, s1.x is uninitialized. In the original non-POD case it was the
same way where the default initialization of pod2 caused the int member
to be uninitialized and the vector member to be default constructed.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
11/30/2003 11:09:10 PM
|
|
On 30 Nov 2003 05:32:18 -0500, Graeme Prentice <deepblue57x@yahoo.co.nz>
wrote:
> On 29 Nov 2003 14:45:34 -0500, John Potter <jpotter@falcon.lhup.edu>
> wrote:
> >struct S { int x; };
> >void f () {
> > S s1; // s1.x is uninitialized
> > S s2 = S(); // s2.x is zero
> > }
> >
> >The term default constructed seems to have lost meaning.
> No it hasn't, but people often make up their own interpretation of what
> default construction applied to built in types means
S is not a built in type. I am talking about default construction of a
class type.
> because the C++
> standard doesn't define it and Stroustrup and Josuttis claim that it
> means T() which is described in 5.2.3 para 2 as being value
> initialisation which is "zero converted to type T" for built in types.
I guess that we can forgive them because the standard does say what it
means for class types. 12.1/8 states that the default constructor is
implicitely called for a variable without an initializer and for the
explicit type conversion. Does changing the wording in 5.2.3/2 claim
that T() is not an explicit type conversion and does not call the
default constructor although it is in the section of that name?
The default constructor for S called for s1 and new S is
S () { }
but the default constructor for S called for S() and new S() is
S () : x() { }
I wonder how the compiler wrote both of them? 12.8/7 clearly states
that it is the first.
Value initialization has introduced a state of non-sense where it is
no longer possible to claim that class objects are initialized by
constructors. Both uses call the default ctor if the user writes it.
If the compiler writes it, the first calls it, but the second calls no
ctor and magically initializes everything.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
11/30/2003 11:10:14 PM
|
|
On 30 Nov 2003 18:10:14 -0500, John Potter <jpotter@falcon.lhup.edu>
wrote:
Hi John
I think you are probably missing section 8.5 para 9 where it says that
if no initializer is specified for an object, non PODs (or array of) are
default initialized, and PODs are uninitialized.
This could be changed to say that non PODs are default constructed and
PODs are uninitialized and have the same meaning. (default
initialization for a non POD means default construction).
If the standard defined default construction for PODs as doing nothing
(logical in my opinion) then we could say that objects with no
initialiser are default constructed.
Stroustrup's description of default construction for built in types is
that it produces zeroing, which IMO, is inconsistent with the fact that
the "traditional" meaning (AFAIK) of default construction of a POD
struct is "no initialization". In the C++ standard, default
construction is never applied to a POD struct (but if it did, the
definition in 12.1 para 7 would apply). The term "default construction"
does not appear in chapter 23 (containers library) but both Josuttis and
Stroustrup say that for std::vector v1(20), there are 20 default
constructed elements. (In 2003 std terminology, there are 20
value-initialized elements and in 1998 std terminology there are 20
default initialized elements).
I believe the C++ standard was based on Stroustrup's book. In section
6.2.8 he says the constructor notation T() is used to express the
default value of type T and that this is zero for built in types and the
default constructor for user-defined types. Possibly Stroustrup
intended T() and default construction for POD structs to do nothing and
the standardization process decided zeroing was desirable for T() and
came up with "default initialization" (8.5 para 5) but overlooked non
PODs with no constructor (which don't get zeroed according to 1998 std
but do according to 2003 std).
Anyway, I don't want to seem critical of Stroustrup at all as I respect
him a lot, but every time I see people mention "default construction of
built in types" I think to myself "there's no such thing". (sometimes
Stroustrup's book is more meaningful than the standard - as is the case
with his description in 10.4.6.2 of when an out of class definition is
required for a static const int member).
>On 30 Nov 2003 05:32:18 -0500, Graeme Prentice <deepblue57x@yahoo.co.nz>
>wrote:
>
>> On 29 Nov 2003 14:45:34 -0500, John Potter <jpotter@falcon.lhup.edu>
>> wrote:
>
>> >struct S { int x; };
>> >void f () {
>> > S s1; // s1.x is uninitialized
>> > S s2 = S(); // s2.x is zero
>> > }
>> >
>> >The term default constructed seems to have lost meaning.
>
>> No it hasn't, but people often make up their own interpretation of what
>> default construction applied to built in types means
>
>S is not a built in type. I am talking about default construction of a
>class type.
ok, I'm guessing you mean that most people think that POD structs have a
default constructor that does nothing, yet default construction is never
applied to a POD struct by the C++ standard.
>
>> because the C++
>> standard doesn't define it and Stroustrup and Josuttis claim that it
>> means T() which is described in 5.2.3 para 2 as being value
>> initialisation which is "zero converted to type T" for built in types.
>
>I guess that we can forgive them because the standard does say what it
>means for class types. 12.1/8 states that the default constructor is
>implicitely called for a variable without an initializer and for the
>explicit type conversion.
Now that you've read 8.5 para 9, you probably realise that 12.1 para 8
is listing the situations where default constructors are used rather
than defining how an object with no initializer is initialized i.e. it
says "default constructors are called to create class objects ...
defined without an initialiser", which is not the same as saying that
"all class objects defined without an initialiser are default
constructed".
>Does changing the wording in 5.2.3/2 claim
>that T() is not an explicit type conversion and does not call the
>default constructor although it is in the section of that name?
I guess this comment is based on your interpretation of 12.1/8 which you
have possibly reconsidered now.
>
>The default constructor for S called for s1 and new S is
> S () { }
>but the default constructor for S called for S() and new S() is
> S () : x() { }
>
>I wonder how the compiler wrote both of them? 12.8/7 clearly states
>that it is the first.
you mean 12.1/7. 8.5 para 9 applies to s1 which is "no
initialization" and similarly for "new S" (5.3.4 para 15)
>
>Value initialization has introduced a state of non-sense where it is
>no longer possible to claim that class objects are initialized by
>constructors. Both uses call the default ctor if the user writes it.
>If the compiler writes it, the first calls it, but the second calls no
>ctor and magically initializes everything.
I'm not 100% sure what you're saying here but I guess it hinges on 8.5
para 9 that you may not have noticed.
I think that default initialization is now never applied to a POD, so
the definition of default initialization in the 2003 std could remove
the third bullet that applies to PODs. I believe that the definition of
"default initialization" itself could be removed completely from the
standard and replaced with "default construction" wherever it appears.
If the less than wonderful Acrobat reader made searching a bit easier
and reliable, I could say with more certainty.
Despite the fact that I know the C++ standard *relatively* well
regarding this issue, I have great difficulty remembering the precise
meaning of
type object;
- hence my mistake in my other post.
I guess Stroustrup tried to give the notation T() a meaningful name when
he described it as default construction, but that doesn't quite fit with
the need for T() to produce zeroing, which is now value initialization.
"Value initialization" and "default initialization" are a little too
clunky to appear in programming textbooks or for their precise
definitions to be remembered easily.
Maybe we can blame "C" but IMO it's a good thing that a C program can be
compiled as C++ with no change in how objects are initialized.
As you said before, "one point worth repeating is the difference between
no initializer and default (now value) initialization".
#include <vector>
#include <iostream>
struct S { int x; };
struct C { int x; std::vector<int> v; S s; };
void f () {
S s1; // s1.x is uninitialized
S s2 = S(); // s2.x is zero - (value initialize)
C c1; // non POD => default initialize == default construction
C c2 = C(); // value initialize c2
C c3 = {}; // value initialize *members* of c3
std::cout << "\n try this "
<< c2.s.x << " " << c3.s.x;
}
int main()
{
f();
}
Something else worth mentioning is that even when you know all the
rules, the compiler doesn't necessarily know them and GCC 3.2.3 gives a
different result for the above code than Comeau 4.3.3 and Borland 5.5.1
won't even compile it. GCC is probably following the 1998 std and
doesn't zero c2.s.x ( C is a non POD with no constructor) but does zero
c3.s.x because it applies default initialization to the *members* of c3.
But I still like C++ :)
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Graeme
|
12/1/2003 9:46:51 PM
|
|
John Potter <jpotter@falcon.lhup.edu> wrote in message
news:<b8lfsvg8lfrlprhu7oemcnk01pocov44ec@4ax.com>...
> On 28 Nov 2003 12:03:08 -0500, kanze@gabi-soft.fr wrote:
> > John Potter <jpotter@falcon.lhup.edu> wrote in message
> > news:<vl5asvkfmqfvrdpom0k2mcbh9pob78uoag@4ax.com>...
[...]
> > > > POD good_pod2;
> Note lack of initializer.
> > > You should also know that good_pod2 has an uninitialized int not
> > > a zero.
> > I hope not. This would be a gratuious incompatibility with C -- an
> > incredible one, in which C++ was being less safe, and invoking less
> > behind the scenes magic than C. However, as we've just seen, C++
> > uses "default initialization" in this case, and we again have
> > �8.5/6: "[...] -- otherwise, the storage for the object is
> > zero-initialized." In sum, if T is not a non-POD class type (or an
> > array of non-POD class types), we follow the same rules as C.
> Did you miss the above where good_pod2 has no initializer?
Yes. I was reading ahead, where you talk about inversing the order of
the elements. Inversing the order of the elements makes no difference
with regards to initialization, of course. But you didn't say it did.
> > > The compiler generated default ctor does nothing for the int but
> > > calls the vector default ctor.
> > By "compiler generated default constructor" for int, you mean int(),
> > right? Like in the example in �8.5./1/7.
> I'm talking about the compiler generated default constructor for POD
> POD () : data() { }
> It does not initialize nNum.
Agreed. I was thinking of the compiler generated default constructor
for each of the elements, which is used for elements whose initializer
is missing in the case of an agglomerate initialization. That one does
initialize to zero.
Isn't it nice that we have two different behaviors, according to
context.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
12/1/2003 9:48:05 PM
|
|
On 1 Dec 2003 16:46:51 -0500, Graeme Prentice <deepblue57x@yahoo.co.nz>
wrote:
> On 30 Nov 2003 18:10:14 -0500, John Potter <jpotter@falcon.lhup.edu>
> wrote:
> I think you are probably missing section 8.5 para 9 where it says that
> if no initializer is specified for an object, non PODs (or array of) are
> default initialized, and PODs are uninitialized.
Yes, thank you.
> >Value initialization has introduced a state of non-sense where it is
> >no longer possible to claim that class objects are initialized by
> >constructors. Both uses call the default ctor if the user writes it.
> >If the compiler writes it, the first calls it, but the second calls no
> >ctor and magically initializes everything.
> I'm not 100% sure what you're saying here but I guess it hinges on 8.5
> para 9 that you may not have noticed.
I don't think so. See below.
> As you said before, "one point worth repeating is the difference between
> no initializer and default (now value) initialization".
> struct S { int x; };
> struct C { int x; std::vector<int> v; S s; };
> void f () {
> S s1; // s1.x is uninitialized
> S s2 = S(); // s2.x is zero - (value initialize)
> C c1; // non POD => default initialize == default construction
> C c2 = C(); // value initialize c2
> C c3 = {}; // value initialize *members* of c3
C is a non-POD. If I add a default ctor.
C () { }
C2 is the same as c1 and c3 is a syntax error. It is c2 that I was
talking about above. The meaning depends upon whether the default
ctor is user written or not. If it is, it is used. If not, it is
not used and members are value initialized without any ctor involved.
Note that c1 requires declaring and defining the default ctor.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
12/2/2003 10:29:16 AM
|
|
On 2 Dec 2003 05:29:16 -0500, John Potter <jpotter@falcon.lhup.edu>
wrote:
>On 1 Dec 2003 16:46:51 -0500, Graeme Prentice <deepblue57x@yahoo.co.nz>
>wrote:
>
[snip]
> > >Value initialization has introduced a state of non-sense where it is
> > >no longer possible to claim that class objects are initialized by
> > >constructors. Both uses call the default ctor if the user writes it.
> > >If the compiler writes it, the first calls it, but the second calls no
> > >ctor and magically initializes everything.
>
[snip]
>
> > struct S { int x; };
> > struct C { int x; std::vector<int> v; S s; };
>
> > void f () {
> > S s1; // s1.x is uninitialized
> > S s2 = S(); // s2.x is zero - (value initialize)
> > C c1; // non POD => default initialize == default construction
> > C c2 = C(); // value initialize c2
> > C c3 = {}; // value initialize *members* of c3
>
>C is a non-POD. If I add a default ctor.
>
> C () { }
>
>C2 is the same as c1 and c3 is a syntax error. It is c2 that I was
>talking about above. The meaning depends upon whether the default
>ctor is user written or not. If it is, it is used. If not, it is
>not used and members are value initialized without any ctor involved.
>Note that c1 requires declaring and defining the default ctor.
ok, now I see what you were saying (except for the last sentence about
c1)
I disagree that value initialization created a state of nonsense though.
Before value initialization came along, POD class objects always came
into existence without a default constructor being called (according to
the 1998 standard). Now with value initialization, non PODs without a
user declared constructor can also come into existence without the
default constructor being called. From a user point of view, whether
the implicit default constructor is actually called or what name is
given to this form of initialization is a kind of "behind the scenes
technical detail", rather than a state of nonsense IMO - the effect is
(almost) the same.
Defect report 302 discusses this very issue (more or less) and it
appears that the C++ committee would have liked value initialization of
non PODs with no constructor to be implementable as "zero initialization
followed by default construction", however the following type of class
caused a problem
struct B {
const int i;
A a;
};
The definition of the implicitly generated default constructor requires
an error if applied to the above class because 12.6.2 para 4 objects to
the uninitialised POD const member. It was apparently desired that
value initialisation be valid for this case e.g. that B() be legal.
"Zero initialisation followed by default construction" can result in
more zeroing of the object than value initialisation does so it's not
actually the same thing.
BTW if you write a default constructor as e.g. C() : v() {}, then the
element v is value initialised, not default constructed.
I am slightly puzzled at the motivation for T() to produce zeroing for T
being a non POD without a constructor. Classes with a constructor don't
get this facility. I would have thought the motivation for zeroing was
one of efficiency - i.e. if there are many members that need zeroing,
explicitly initialising one by one is inefficient - however, I get the
impression that this may not be the motivation for T() to produce
zeroing for non PODs with no constructor.
BTW2 - people claim C++ is complicated, however if you look at the rules
for initialisation of structs and classes in C#, it is just as
complicated IMO. In C++, if you write your own constructor for a class,
you have complete control, and if you want to take advantage of "T()"
producing zeroing of POD members for T being a class with no
constructor, you have to take some extra care and ensure that the
compiler you use, really does do it. Lots of people probably rely on
vector<int> v(10); producing lots of zeroes but a lot of people probably
don't know what happens when the element type is a non POD with no
constructor or when it's a POD struct.
Graeme
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Graeme
|
12/2/2003 10:01:56 PM
|
|
|
19 Replies
203 Views
(page loaded in 0.226 seconds)
Similiar Articles: Aggregate initializers of static objects - comp.lang.c++.moderated ...Hello, lets start with the code. // code begin static int data[] = {1, 2, 3, std::accumulate(data, data+4, 0)}; // code end The question ... How to fix "invalid super-block" on HP-UX 11.00? - comp.sys.hp ...(ynq)y > alternate super-block not found > vxfs fsck: cannot initialize aggregate > file system check failure, aborting ... > > [root@rddb#/] > > > how can I fix this ... Static const integral data members can be initialized? - comp.lang ...One can easily obtain the same effect as initialization within the class definition ... Aggregate initializers of static objects - comp.lang.c++.moderated ... Static const ... initializer must be constant error bug? - comp.compilers.lcc ...Aggregate initializers of static objects - comp.lang.c++.moderated ... initializer ... Initialization of reference to non-const - comp.lang.c++.moderated ... initializer must ... Const constructor - comp.lang.c++.moderated... have aggregate<int const> and aggregate<int> However, how do we define a constructor from aggregate<int> to aggregate<const int>? I would like to be able to initialize a ... Initializing Aggregate TypesAn "aggregate" type is a structure, union, or array type. If an aggregate type contains members of aggregate types, the initialization rules apply recursively. Initializing Aggregate Types (C)An "aggregate" type is a structure, union, or array type. If an aggregate type contains members of aggregate types, the initialization rules apply recursively. 7/16/2012 5:45:50 AM
|