Smart pointers and this

S

sip.address

I'm using reference counted smart pointers in a small project and it's
a breeze, but I'm running into a problem which I don't know how to
approach.

Consider something like this:

class A {
public:
A() {}
void setObserver(counted_ptr<B> observer) { _observer =
observer; }

private:
counted_ptr<B> _observer;
};

class B {
public:
B() {
_a = counted_ptr<A>(new A);
_a->setObserver(counted_ptr<B>(this));
}

private:
From what I can see, the problem is creating a smart pointer with an
already existing raw pointer. In this case, the problem is that when
A's destructor is called (while B is being destroyed), it will destroy
_observer, which having a ref count of 1, will delete the pointed
object (B), which is not a good thing.

The easiest alternative I thought for this case is using a reference
instead, but I'd like to know if there's some way to fix this problem
(having an extra reference to avoid deletion somehow, etc)

Thanks!
 
J

Joe Gottman

I'm using reference counted smart pointers in a small project and it's
a breeze, but I'm running into a problem which I don't know how to
approach.

Consider something like this:

class A {
public:
A() {}
void setObserver(counted_ptr<B> observer) { _observer =
observer; }

private:
counted_ptr<B> _observer;
};

class B {
public:
B() {
_a = counted_ptr<A>(new A);
_a->setObserver(counted_ptr<B>(this));
}

private:

already existing raw pointer. In this case, the problem is that when
A's destructor is called (while B is being destroyed), it will destroy
_observer, which having a ref count of 1, will delete the pointed
object (B), which is not a good thing.

The easiest alternative I thought for this case is using a reference
instead, but I'd like to know if there's some way to fix this problem
(having an extra reference to avoid deletion somehow, etc)

Your best bet is to use boost::shared_ptr and boost::weak_ptr. See
http://www.boost.org/libs/smart_ptr/smart_ptr.htm for more information.

Joe Gottman
 
G

Gianni Mariani

I'm using reference counted smart pointers in a small project and it's
a breeze, but I'm running into a problem which I don't know how to
approach.

Consider something like this:

class A {
public:
A() {}
void setObserver(counted_ptr<B> observer) { _observer =
observer; }

private:
counted_ptr<B> _observer;
};

class B {
public:
B() {
_a = counted_ptr<A>(new A);
_a->setObserver(counted_ptr<B>(this));
}

private:

already existing raw pointer. In this case, the problem is that when
A's destructor is called (while B is being destroyed), it will destroy
_observer, which having a ref count of 1, will delete the pointed
object (B), which is not a good thing.

A & B objects would never get deleted. You need to decide who owns who.
You then need a smart pointer type that does not assume ownership
(usually referred to as a weak pointer). Austria C++ uses Ptr and
PtrView (Ptr for ownership and PtrView as a weak pointer). Boost I
think uses shared_ptr and weak_ptr.
The easiest alternative I thought for this case is using a reference
instead, but I'd like to know if there's some way to fix this problem
(having an extra reference to avoid deletion somehow, etc)

This is a design issue. Cyclic graphs of smart pointers must be avoided
in your design, otherwise you will have issues.
 
S

sip.address

Your best bet is to use boost::shared_ptr and boost::weak_ptr. Seehttp://www.boost.org/libs/smart_ptr/smart_ptr.htmfor more information.

Aha! seems that I'm not the first one having this problem.. Many
thanks, this looks interesting, although the FAQ at the end of this
page http://www.boost.org/libs/smart_ptr/weak_ptr.htm seems to say
that I can't use this as intended in the example snippet (inside a
ctor). Anyway I'll search for further info about these weak pointers.
Thanks for the hint.
 
S

sip.address

Aha! seems that I'm not the first one having this problem.. Many
thanks, this looks interesting, although the FAQ at the end of this
pagehttp://www.boost.org/libs/smart_ptr/weak_ptr.htmseems to say
that I can't use this as intended in the example snippet (inside a
ctor). Anyway I'll search for further info about these weak pointers.
Thanks for the hint.

I would also like to thank Gianni Mariani and Tim H for their helpful
replies. Unfortunately it seems that google news don't display them
for some reason (I only get to see 3 of the 5 messages in the thread!)

Regarding Gianni's last point:
This is a design issue. Cyclic graphs of smart pointers must be avoided
in your design, otherwise you will have issues.

The only thing I'm expecting to use is a simple observer facility. A
parent class creates a child class, and needs to get notified of some
events generated by this child class. So after instantiating the
child, I register the parent to listen for events. I think this is the
easiest way to achieve this. Are there better alternatives?

Thank you.
 
G

Gianni Mariani

On Sep 19, 1:53 am, (e-mail address removed) wrote: ....

The only thing I'm expecting to use is a simple observer facility. A
parent class creates a child class, and needs to get notified of some
events generated by this child class. So after instantiating the
child, I register the parent to listen for events. I think this is the
easiest way to achieve this. Are there better alternatives?

The Austria C++ library has a concept call "Twins". A twin consists of
a "Lead" and an "Aide". The twin relationship does not constrain the
life of one or the other. When one of them is deleted, the other is
notified.

The Lead usually requests some kind of service from an Aide and the aide
then "associates" with the lead (through the twin interface). The lead
can "cancel" the association with the lead, similarly, the aide can
cancel the lead. Destruction is an automatic cancel, however care needs
to be taken that in an MT environment, the cancel happens in the most
derived calls.

The most recent alpha of Austria C++ (available here)
http://netcabletv.org/public_releases/ contains a multithreaded version
of Twins which is used in the networking and timer functionality.

I don't think I've seen the "observer" terminology used consistently so
I've purposely not used it here.

The templates are a little tricky but the unit tests should show you how
it's used. The version of the Austria C++ library on sourceforge has
the non threaded version of twins.

Implementing a multithreaded "twin" is very tricky and it is good to use
thread pools to avoid issues with deadlocks.
 
J

James Kanze

I'm using reference counted smart pointers in a small project and it's
a breeze, but I'm running into a problem which I don't know how to
approach.
Consider something like this:
class A {
public:
A() {}
void setObserver(counted_ptr<B> observer) { _observer =
observer; }
private:
counted_ptr<B> _observer;
};
class B {
public:
B() {
_a = counted_ptr<A>(new A);
_a->setObserver(counted_ptr<B>(this));
}
private:
counted_ptr<A> _a;
};
From what I can see, the problem is creating a smart pointer with an
already existing raw pointer. In this case, the problem is that when
A's destructor is called (while B is being destroyed), it will destroy
_observer, which having a ref count of 1, will delete the pointed
object (B), which is not a good thing.

Presumably, your counted_ptr is similar to boost::shared_ptr.
If so, you're misusing it. It represents *shared* ownership
(which is actually pretty rare), and the observer pattern
doesn't involve ownership. It's pure navigation, which means
that you should probably be using raw pointers (although there
are special cases when some other type of smart pointer might be
appropriate).
The easiest alternative I thought for this case is using a
reference instead, but I'd like to know if there's some way to
fix this problem (having an extra reference to avoid deletion
somehow, etc)

Just use a raw pointer. In general, when pointers are used for
navigation, rather than for ownership, raw pointers are the most
appropriate solution.
 
W

werasm

(e-mail address removed) wrote:

Regarding Gianni's last point:


The only thing I'm expecting to use is a simple observer facility. A
parent class creates a child class, and needs to get notified of some
events generated by this child class. So after instantiating the
child, I register the parent to listen for events. I think this is the
easiest way to achieve this. Are there better alternatives?

While it can be noted that cyclic graphs must be avoided, weak
pointers can break these cycles. I've had problems very
recently where I attempted to write a generic
subscriber/observer which, if you inherited from it automatically
subscribed during construction, and unsubscribed at destruction.

The problem was that one could not use normal pointers, as
the subject (publisher) then had to notify its observers when
it got deleted so the observers who kept a reference did not call
unsubscribe on the invalid reference. To take it further, one part
of the application was decoupled from another by observing the
other and visa versa, therefore one had not choice but either
explicitly unsubscribe, or face UB. The solution was simply to
use weak pointers conservatively. One could probably have used
policies, making weak_ptr the default policy, and allowing the
user to define a reference or pointer policy if he chooses.

Regards,

Werner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top