473,396 Members | 1,915 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Initializer list and instance variables

Can I use an instance variable as an argument in an initialiser list as
follows:

class bar
{
private:
int i1_;
public:
bar(int i1):i1_(i1){}
};

class fooBase
{
private:
bar& ref_my_bar_;
public:
fooBase(bar& ref_my_bar):ref_my_bar_(ref_my_bar){}
virtual ~fooBase(void){}
};

class fooDerived:public fooBase
{
private:
bar my_bar_;
public:
fooDerived(void):fooBase(my_bar_),my_bar_(42){} // ???
virtual ~fooDerived(void){}
};

This compiles OK, and intuitively I'd have thought it was safe whether
fooBase(my_bar_) or my_bar_(42) gets executed first. I'm simply passing
a reference down to a base class, and whether my_bar_'s constructor
gets called before or after this should make no odds.

Does the standard mandate any particular order of execution for this
combination?

Is what I'm doing safe in general, or are there times when this
approach won't do what I'd expect?
--
Simon Elliott http://www.ctsn.co.uk
Jul 22 '05 #1
5 1303
Simon Elliott wrote:
Can I use an instance variable as an argument in an initialiser list as
follows:

class bar
{
private:
int i1_;
public:
bar(int i1):i1_(i1){}
};

class fooBase
{
private:
bar& ref_my_bar_;
public:
fooBase(bar& ref_my_bar):ref_my_bar_(ref_my_bar){}
virtual ~fooBase(void){}
};

class fooDerived:public fooBase
{
private:
bar my_bar_;
public:
fooDerived(void):fooBase(my_bar_),my_bar_(42){} // ???
virtual ~fooDerived(void){}
};

This compiles OK, and intuitively I'd have thought it was safe whether
fooBase(my_bar_) or my_bar_(42) gets executed first. I'm simply passing
a reference down to a base class, and whether my_bar_'s constructor
gets called before or after this should make no odds.

Does the standard mandate any particular order of execution for this
combination?
The order of initialising is (1) base classes in the order of their
declaration, then (2) the members in the order of their declaration
in the class.
Is what I'm doing safe in general, or are there times when this
approach won't do what I'd expect?


What you do is rather unsafe. The 'my_bar_' does not yet represent
a complete object of type 'bar' at the time of initialising of 'fooBase'.
While in your particular example 'fooBase' only stores the reference to
the object with which it is initialised, somebody can later come in and
change the behaviour of 'fooBase' to actually do something with the
object of type 'bar' in the constructor, thinking that the reference is
to a good and complete object. An attempt to call a member function for
an object that hasn't been constructed yet causes undefined behaviour,
IIRC.

Victor
Jul 22 '05 #2
On 20/09/2004, Victor Bazarov wrote:
Does the standard mandate any particular order of execution for this
combination?


The order of initialising is (1) base classes in the order of their
declaration, then (2) the members in the order of their declaration
in the class.


So in my example, the base class constructor gets called before my_bar_
is initialised.
Is what I'm doing safe in general, or are there times when this
approach won't do what I'd expect?


What you do is rather unsafe. The 'my_bar_' does not yet represent
a complete object of type 'bar' at the time of initialising of
'fooBase'. While in your particular example 'fooBase' only stores
the reference to the object with which it is initialised, somebody
can later come in and change the behaviour of 'fooBase' to actually
do something with the object of type 'bar' in the constructor,
thinking that the reference is to a good and complete object. An
attempt to call a member function for an object that hasn't been
constructed yet causes undefined behaviour, IIRC.


So at the very least I need a comment in the constructor telling folk
not to mess with ref_my_bar_.

Is there a safer way of achieving this? I suppose I could do:

class fooBase
{
private:
bar* ptr_my_bar_;
public:
fooBase(void):ptr_my_bar_(0){}
virtual ~fooBase(void){}
void SetBar(ptr_my_bar){ptr_my_bar_=ptr_my_bar;}
};

class fooDerived:public fooBase
{
private:
bar my_bar_;
public:
fooDerived(void):fooBase(),my_bar_(42){SetBar(&my_ bar_);}
virtual ~fooDerived(void){}
};

But in this case ptr_my_bar_ starts life as a null pointer. I suppose
that at least it's fairly obvious that this is the case. But a
developer coding a new fooDerived could forget to call
fooBase::SetBar(), ptr_my_bar_ would be null during all of fooBase
lifetime, and the error would not be caught at compile time.
--
Simon Elliott http://www.ctsn.co.uk
Jul 22 '05 #3
Simon Elliott wrote:
On 20/09/2004, Victor Bazarov wrote:

Does the standard mandate any particular order of execution for this
combination?
The order of initialising is (1) base classes in the order of their
declaration, then (2) the members in the order of their declaration
in the class.

So in my example, the base class constructor gets called before my_bar_
is initialised.


Yes. The memory for the 'my_bar_' subobject has been allocated, but its
constructor has not been called. So, the object 'my_bar_' doesn't really
exist yet at that point.
Is what I'm doing safe in general, or are there times when this
approach won't do what I'd expect?


What you do is rather unsafe. The 'my_bar_' does not yet represent
a complete object of type 'bar' at the time of initialising of
'fooBase'. While in your particular example 'fooBase' only stores
the reference to the object with which it is initialised, somebody
can later come in and change the behaviour of 'fooBase' to actually
do something with the object of type 'bar' in the constructor,
thinking that the reference is to a good and complete object. An
attempt to call a member function for an object that hasn't been
constructed yet causes undefined behaviour, IIRC.

So at the very least I need a comment in the constructor telling folk
not to mess with ref_my_bar_.


I say.
Is there a safer way of achieving this? I suppose I could do:

class fooBase
{
private:
bar* ptr_my_bar_;
public:
fooBase(void):ptr_my_bar_(0){}
virtual ~fooBase(void){}
void SetBar(ptr_my_bar){ptr_my_bar_=ptr_my_bar;}
You mean

void SetBar(bar*ptr_my_bar){ptr_my_bar_=ptr_my_bar;}
};

class fooDerived:public fooBase
{
private:
bar my_bar_;
public:
fooDerived(void):fooBase(),my_bar_(42){SetBar(&my_ bar_);}
virtual ~fooDerived(void){}
};

But in this case ptr_my_bar_ starts life as a null pointer. I suppose
that at least it's fairly obvious that this is the case. But a
developer coding a new fooDerived could forget to call
fooBase::SetBar(), ptr_my_bar_ would be null during all of fooBase
lifetime, and the error would not be caught at compile time.


All is true. That's why making the base class depend on an object in
a derived class is not such a great design solution.

Victor
Jul 22 '05 #4
On 21/09/2004, Victor Bazarov wrote:
That's why making the base class depend on an object in
a derived class is not such a great design solution.


The problem here is:

1/ In the real design, fooDerived needs a class which inherits from a
bar. The base class needs to talk to the interface of barBase, but the
derived class needs to talk to the extra functionality implemented by
barDerived. There will be lots of fooDerived, each with their
corresponding barDerived. (ie there will be a fooDerivedA with a
barDerivedA, a fooDerivedB with a barDerivedB, etc)

2/ I might have handled this using inheritance (although even that
would be imperfect as a foo HAS a bar but a foo IS NOT a bar.) That
way, I wouldn't need to pass a pointer to barDerived down to fooBase.
But as it happens, fooDerived needs two instances of barDerived.

So I'm looking at some alternate designs, perhaps integrating the two
objects into a fooBarBase...

--
Simon Elliott http://www.ctsn.co.uk
Jul 22 '05 #5
Simon Elliott wrote:
[...]
So I'm looking at some alternate designs, perhaps integrating the two
objects into a fooBarBase...


Post to comp.object, they are really good with suggesting designs.

V
Jul 22 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

26
by: Alex Panayotopoulos | last post by:
Hello all, Maybe I'm being foolish, but I just don't understand why the following code behaves as it does: - = - = - = - class listHolder: def __init__( self, myList= ): self.myList =...
1
by: Chris K | last post by:
I am relatively new to C++ and hope that this question is relevant. I have spent some time at the local library and some time on dejanews, but have no decided to go ahead with my question, since...
6
by: ahart | last post by:
I'm pretty new to python and am trying to write a fairly small application to learn more about the language. I'm noticing some unexpected behavior in using lists in some classes to hold child...
2
by: cody | last post by:
class Test { IList list = new ArrayList(); MyCollection list2 = new MyCollection (list); } Leads to this error. I know I could initialize them in the ctor but I'm asking myself where this...
2
by: aarklon | last post by:
Hi all, Recently i was reading a c book which contained a section called C pitfalls. it had a paragraph on the following lines:- ...
3
by: Ham Pastrami | last post by:
class Point { public: const int x, y; Point(int x, int y); } Point::Point(int x, int y) : x(x), y(y) { }
6
by: Marvin Barley | last post by:
I have a class that throws exceptions in new initializer, and a static array of objects of this type. When something is wrong in initialization, CGI program crashes miserably. Debugging shows...
3
by: Steven D'Aprano | last post by:
I have a class that has a distinct "empty" state. In the empty state, it shouldn't have any data attributes, but it should still have methods. The analogy is with a list: an empty list still has...
5
by: Pallav singh | last post by:
How can we justify that initializer list is better in performance than assignment list in constructor of C++ ??
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.