By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,804 Members | 1,634 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,804 IT Pros & Developers. It's quick & easy.

How is member initialisation ordered?

P: n/a
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.
Jul 22 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
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
rg********@pobox.com
Remove the 'g' from my address to send me mail.

Jul 22 '05 #2

P: n/a
"Jason Heyes" <ge******@optusnet.com.au> wrote in message
news:3f***********************@news.optusnet.com.a 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
Jul 22 '05 #3

P: n/a
On Wed, 3 Dec 2003 17:13:23 +1100, "Jason Heyes"
<ge******@optusnet.com.au> 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.
Jul 22 '05 #4

P: n/a

"Dan W." <da**@raytron-controls.com> schrieb im Newsbeitrag
news:4i********************************@4ax.com...
On Wed, 3 Dec 2003 17:13:23 +1100, "Jason Heyes"
<ge******@optusnet.com.au> 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 theorder 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
Jul 22 '05 #5

P: n/a
"Norbert Riedlin" <nr@netatec.de> wrote in message
news:bq*************@ID-212925.news.uni-berlin.de...

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.
Jul 22 '05 #6

P: n/a
>
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
Jul 22 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.