470,815 Members | 1,084 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,815 developers. It's quick & easy.

Passing *this in constructor

Hi, thanks for help in previous post. I've made the class objects i
need data members so
i now initialise in constructor. However some of my subobjects need to
have a reference to their
owner object.

Can i do the following then ie pass *this in the constructor of A, i
was concerned maybe the
A object is not fully constructed. If this is not way to do how to do?

/.h file
class A
{
public:
A();
~A();
private:

obj1 myobj1;

};
/.cpp file

A::A()
: myobj1(*this) <- CHANGE MADE HERE
{

}

A::~A()
{
}
Obviously constructor of obj1 takes reference to A

class obj1
{
private:
obj1& m_obj;
};

obj1(A& a):m_obj(a)
{
}

Jun 27 '08 #1
7 1516
tech wrote:
Hi, thanks for help in previous post. I've made the class objects i
need data members so
i now initialise in constructor. However some of my subobjects need to
have a reference to their
owner object.

Can i do the following then ie pass *this in the constructor of A, i
was concerned maybe the
A object is not fully constructed. If this is not way to do how to do?

/.h file
class A
{
public:
A();
~A();
private:

obj1 myobj1;

};
/.cpp file

A::A()
: myobj1(*this) <- CHANGE MADE HERE
{

}

A::~A()
{
}
Obviously constructor of obj1 takes reference to A

class obj1
{
private:
obj1& m_obj;
I think you meant

A& m_obj;
};

obj1(A& a):m_obj(a)
{
}


The answer is "Yes, you can". Be careful, though, not to call any
member functions or access any data members of 'a' in the 'obj1'
constructor because 'a' hasn't been fully constructed yet.
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 27 '08 #2
Hi!

James Kanze schrieb:
The answer is "yes, you can" in this simple case. If the object
expects a reference to a base class, however, you have undefined
behavior (and I've encountered cases where it doesn't work),
since conversion to base is also undefined behavior.
Wait a second. What's that? Has the following undefined behaviour?

struct Foo {
private:
//..lots of member variables needing initialisation
string name;
Bar whatever;
protected:
void run();
};

struct Runner : Foo
{
Runner();
~Runner();
boost::thread myThread;
};

Runner::Runner()
: Foo()
, myThread(bind(&Foo::run, this))
{}
Runner::~Runner()
{
myThread.interrupt();
myThread.join();
}

Maybe this doesn't actually force the conversion of "this" to "Foo*",
but it's an example of what I currently need in some code. I just want
to know some rules about this. So when does it become dangerous?

Frank
Jun 27 '08 #3
Frank Birbacher wrote:
Hi!

James Kanze schrieb:
>The answer is "yes, you can" in this simple case. If the object
expects a reference to a base class, however, you have undefined
behavior (and I've encountered cases where it doesn't work),
since conversion to base is also undefined behavior.

Wait a second. What's that? Has the following undefined behaviour?

struct Foo {
private:
//..lots of member variables needing initialisation
string name;
Bar whatever;
protected:
void run();
};

struct Runner : Foo
{
Runner();
~Runner();
boost::thread myThread;
};

Runner::Runner()
: Foo()
, myThread(bind(&Foo::run, this))
{}
Runner::~Runner()
{
myThread.interrupt();
myThread.join();
}

Maybe this doesn't actually force the conversion of "this" to "Foo*",
but it's an example of what I currently need in some code. I just want
to know some rules about this. So when does it become dangerous?
See 12.7/2. I can't claim full understanding of it, but it seems to say
that since in your code the construction of 'Foo' has completed by the
time 'myThread' is initialised by 'bind', it's OK. Conversion of 'this'
into 'Foo' would have undefined behaviour in this case:

class Foo;
class Bar {
public:
Bar(Foo*); // needs a pointer to Foo
};

class Fubar : public Bar, public Foo {
public:
Fubar() : Bar(this), Foo() {}
};

Note, that the Bar subobject is initialised before the construction of
the 'Foo' subobject begins.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 27 '08 #4
Hi!

Victor Bazarov schrieb:
Note, that the Bar subobject is initialised before the construction of
the 'Foo' subobject begins.
Ok. That's fine.

However James seemed to say you cannot cast "*this" into a base class
reference:

struct Base {};
struct HoldBase {
HoldBase(Base&);
};

struct Derived : Base {
Derived()
: Base(), hold(*this)
{}
HoldBase hold;
};

This transforms "*this" into a base class reference during
initialization. I interpreted James posting this way and concluded the
above must be invalid/undefined behaviour. And this seems rather odd,
don't you think?

Frank
Jun 27 '08 #5
On Jun 7, 1:13 am, Frank Birbacher <bloodymir.c...@gmx.netwrote:
Victor Bazarov schrieb:
Note, that the Bar subobject is initialised before the
construction of the 'Foo' subobject begins.
However James seemed to say you cannot cast "*this" into a
base class reference:
struct Base {};
struct HoldBase {
HoldBase(Base&);
};
struct Derived : Base {
Derived()
: Base(), hold(*this)
{}
HoldBase hold;
};
This transforms "*this" into a base class reference during
initialization. I interpreted James posting this way and
concluded the above must be invalid/undefined behaviour. And
this seems rather odd, don't you think?
It is undefined behavior, and I think it rather odd, too. The
reason I know it's undefined behavior, however, is that I ran
into an actual case where it didn't work, went to write up a
compiler bug report, and when trying to find where the standard
said it had to work, found just the opposite.

One way around it is to use a wrapper class which returns the
pointer---you can't convert the pointer, but you can call member
funtions on fully constructed sub-objects, so something like:

template< typename Base >
struct BaseWrapper
{
Base object ;
Base* ptr() ;
Base& ref() ;
} ;

struct Derived : BaseWrapper< Base >
: hold( ref() )
{
} ;

Although useful in some specific cases (I use it when deriving
from both a specific streambuf and istream or ostream), it is
awkward and overly complex in the general case. And if the
compiler is required to get its pointer conversions correct in
this case, why can't it do so in the other case?

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #6
Hi!

James Kanze schrieb:
It is undefined behavior, and I think it rather odd, too. The
reason I know it's undefined behavior, however, is that I ran
into an actual case where it didn't work, went to write up a
compiler bug report, and when trying to find where the standard
said it had to work, found just the opposite.
Eeew. That's bad!
One way around it is to use a wrapper class which returns the
pointer---you can't convert the pointer, but you can call member
funtions on fully constructed sub-objects, so something like:
Or like:

struct Foo
{
//...here reguar definition
protected:
Foo* ptr() { return this; }
Foo* ref() { return *this; }
};

struct Dev : Foo
{
Dev();
Foo& useless;
};

Dev::Dev()
: Foo(), useless(Foo::ref())
{}

Would that be ok?

I call this a serious defect in the standard. Like you said, you didn't
expect undefined behaviour here anywhere. The conversion is simple to do
because it is needed for calling base class functions anyway. The above
ptr() and ref() methods show an easy implementation and proof this can
be done easily. Not specifying behaviour for conversions here is just a
dangerous pitfall!

Any chance this could be fixed in C++0x?

Frank
Jun 27 '08 #7
Hi!

James Kanze schrieb:
That's boost::bind, right. A template. So the function will
adopt to the type of this, and no conversion will be necessary.
Actually a conversion is eventually necessary: in calling the base class
run() method. If "target" was a pointer to the derived class, would
target ->* (&Base::run)();
include an undefined conversion? This conversion would take place in a
different thread but because of this might as well be done still during
initialization of Derived.
This is a problem with a lot of home built thread classes,
which, even worse, will offen convert the derived this to a
void* (legal, but...), only to convert the void* to Base* (and
not Derived*) in the start up routine.
Woah, bad bad bad. No more torture using void pointers please. ;)
The problem here is elsewhere:
Right, design could be better. I'm still working on it. It's a local
definition for instantiating a static variable which is used as a
singleton. It has had more problems before I refactored it to use boost
thread.

Frank
Jun 27 '08 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Sören | last post: by
13 posts views Thread by Abe Frohnman | last post: by
7 posts views Thread by Ken Allen | last post: by
4 posts views Thread by nickcleary1 | last post: by
12 posts views Thread by dave_dp | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.