Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > How is member initialisation ordered?

Reply
Thread Tools

How is member initialisation ordered?

 
 
Jason Heyes
Guest
Posts: n/a
 
      12-03-2003
Here is a program that doesn't work as intended:

#include <iostream>
using namespace std;

class MyClass
{
int bar;
int foo;
public:
MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo) { }
void print() const { cout << foo << " " << bar << endl; }
};

int main()
{
MyClass obj(3,6);
obj.print(); // intended to show "3 9" but doesn't
return 0;
}

When I reverse the order in which members foo and bar are declared, the
program works properly. It appears as though members are initialised in the
order in which they are declared. Is this gaurenteed? Thanks.


 
Reply With Quote
 
 
 
 
Russell Hanneken
Guest
Posts: n/a
 
      12-03-2003
Jason Heyes wrote:
> It appears as though members are initialised in the order in which they
> are declared. Is this gaurenteed?


Yes, it is. See section 12.6.2/5 of the C++ standard.

--
Russell Hanneken

Remove the 'g' from my address to send me mail.



 
Reply With Quote
 
 
 
 
Phlip
Guest
Posts: n/a
 
      12-03-2003
"Jason Heyes" <> wrote in message
news:3fcd7f04$0$13968$ u...
> Here is a program that doesn't work as intended:
>
> #include <iostream>
> using namespace std;
>
> class MyClass
> {
> int bar;
> int foo;
> public:
> MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo) { }
> void print() const { cout << foo << " " << bar << endl; }
> };
>
> int main()
> {
> MyClass obj(3,6);
> obj.print(); // intended to show "3 9" but doesn't
> return 0;
> }
>
> When I reverse the order in which members foo and bar are declared, the
> program works properly. It appears as though members are initialised in

the
> order in which they are declared. Is this gaurenteed? Thanks.


The rule of thumb: The compiler tries to ensure everything destructs in
order reversed from their construction. (You should match this rule among
allocations and de-allocations.)

Hence, everything constructs in a known, defined order. Inside one class,
this order is top-to-bottom for each members.

That's why lint programs will complain when members appear to construct out
of order.

Even if you obey that rule, and construct bar before foo, don't abuse your
knowledge of the mechanics to indulge in prank construction arguments.
Reading a member inside another member's constructor should be well outside
everyone's "sane subset".

Further, the code above causes undefined behavior. 'bar(bar_ + foo)' reads
the member 'foo' before it has constructed. In practice this only means
'foo' returns garbage, but in theory "undefined behavior" means anything
could happen. For example, if 'foo' somehow occupied memory not yet switched
by hardware to permit reads, the program would crash.

--
Phlip


 
Reply With Quote
 
Dan W.
Guest
Posts: n/a
 
      12-03-2003
On Wed, 3 Dec 2003 17:13:23 +1100, "Jason Heyes"
<> wrote:

>Here is a program that doesn't work as intended:
>
>#include <iostream>
>using namespace std;
>
>class MyClass
>{
> int bar;
> int foo;
>public:
> MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo) { }
> void print() const { cout << foo << " " << bar << endl; }
>};
>
>int main()
>{
> MyClass obj(3,6);
> obj.print(); // intended to show "3 9" but doesn't
> return 0;
>}
>
>When I reverse the order in which members foo and bar are declared, the
>program works properly. It appears as though members are initialised in the
>order in which they are declared. Is this gaurenteed? Thanks.
>


Yup, order of member declaration in the class, not in the
constructor's initializer list. I think you can violate it by moving
the initializations into the body of the constructor, not that it
would be a good idea.
 
Reply With Quote
 
Norbert Riedlin
Guest
Posts: n/a
 
      12-03-2003

"Dan W." <> schrieb im Newsbeitrag
news:...
> On Wed, 3 Dec 2003 17:13:23 +1100, "Jason Heyes"
> <> wrote:
>
> >Here is a program that doesn't work as intended:
> >
> >#include <iostream>
> >using namespace std;
> >
> >class MyClass
> >{
> > int bar;
> > int foo;
> >public:
> > MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo) { }
> > void print() const { cout << foo << " " << bar << endl; }
> >};
> >
> >int main()
> >{
> > MyClass obj(3,6);
> > obj.print(); // intended to show "3 9" but doesn't
> > return 0;
> >}
> >
> >When I reverse the order in which members foo and bar are declared, the
> >program works properly. It appears as though members are initialised in

the
> >order in which they are declared. Is this gaurenteed? Thanks.
> >

>
> Yup, order of member declaration in the class, not in the
> constructor's initializer list. I think you can violate it by moving
> the initializations into the body of the constructor, not that it
> would be a good idea.


No, that would be assignements. The initialization would still happen in the
order
of the declaration. But I think it would be a good idea, at least in the
case of ints
to assign them in the body rather than relying on the order of the members
in the
header file. But even better would be:
class MyClass {
....
MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo_) { } // note
the underscore in foo_

CU
Norbert


 
Reply With Quote
 
Jason Heyes
Guest
Posts: n/a
 
      12-03-2003
"Norbert Riedlin" <> wrote in message
news:bql2uh$240u16$...
>
> No, that would be assignements. The initialization would still happen in

the
> order
> of the declaration. But I think it would be a good idea, at least in the
> case of ints
> to assign them in the body rather than relying on the order of the members
> in the
> header file. But even better would be:
> class MyClass {
> ...
> MyClass(int foo_, int bar_) : foo(foo_), bar(bar_ + foo_) { } // note
> the underscore in foo_
>
> CU
> Norbert


Yes that is better. What happens when members have non-trivial
initialisation? Here is an example:

class MyClass
{
Bar bar; // Bar has constructor with a Foo object parameter
Foo foo;

Foo make_foo(std::string name); // involves some serious work

public:
MyClass(std::string name) : foo(make_foo(name)), bar(foo) { }
};

I could write

MyClass(std::string name) : foo(make_foo(name)), bar(make_foo(name)) { }

but that involves calling make_foo twice. I think I'd better declare the
members in the right order instead.


 
Reply With Quote
 
Norbert Riedlin
Guest
Posts: n/a
 
      12-04-2003
>
> Yes that is better. What happens when members have non-trivial
> initialisation? Here is an example:
>
> class MyClass
> {
> Bar bar; // Bar has constructor with a Foo object parameter
> Foo foo;
>
> Foo make_foo(std::string name); // involves some serious work
>
> public:
> MyClass(std::string name) : foo(make_foo(name)), bar(foo) { }
> };
>
> I could write
>
> MyClass(std::string name) : foo(make_foo(name)), bar(make_foo(name))

{ }
>
> but that involves calling make_foo twice. I think I'd better declare the
> members in the right order instead.
>


You are right. Always declare the members in the right order, but don't
depend on it.
You might be faced with classes written by other developers or with your
classes
changed by other developers. Some compilers warn about not following the
guideline,
but others don't.

Your make_foo() function is a good starter, but, as you mustnot depend on
non-statics
in MyClass, make make_foo() static if possible. (And think twice, if it's
not possible)
Making make_foo() a non-member might even be the option I would choose (And
of
course, change the type of the parameter to const std::string&)

Hm... While thinking about this "calling make_foo() twice" in your example,
I thought
about the following "sollution":

Foo make_foo(const std::string& name) {
//...
}

class MyClass {
Bar bar; // Bar has constructor with a const Foo& parameter
Foo foo;

MyClass(const std::string& name) : bar(foo(make_foo(name))) { }
}

I think this is highly undefined behaviour, because there are two
contradicting concepts:
1. parameters are evaluated, before a call is actually performed
2. members are initialized from top to bottom

As of rule 1, first make_foo() should be called, which in turn is used to
initialize foo, which in
turn is used to initialize bar. // note: foo initialized before bar!
Rule two mandates, that bar must be initialized with foo, then foo will be
initialized.

What is happenig here?

TIA
Norbert


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
Initialisation of reference vs. initialisation of reference member Tim Clacy C++ 8 05-30-2006 06:14 PM
member const initialisation santosh C++ 3 05-23-2005 03:09 PM
CRT, Member Initialisation, static data, constant data, global objects Tim C++ 2 12-15-2003 07:15 PM
String operations in member initialisation list Samuele Armondi C++ 4 06-25-2003 07:59 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57