Smart pointers and this

Discussion in 'C++' started by sip.address@gmail.com, Sep 19, 2007.

  1. Guest

    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.

    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!
    , Sep 19, 2007
    #1
    1. Advertising

  2. Joe Gottman Guest

    wrote:
    > 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.
    >
    > 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
    Joe Gottman, Sep 19, 2007
    #2
    1. Advertising

  3. wrote:
    > 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.


    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.
    Gianni Mariani, Sep 19, 2007
    #3
  4. Guest

    > 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.
    , Sep 19, 2007
    #4
  5. Tim H Guest

    On Sep 18, 4:53 pm, wrote:
    > > Your best bet is to use boost::shared_ptr and boost::weak_ptr. Seehttp://www.boost.org/libs/smart_ptr/smart_ptr.htmformore 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
    > 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.


    boost:enable_shared_from_this
    Tim H, Sep 19, 2007
    #5
  6. Guest

    On Sep 19, 1:53 am, wrote:
    > > Your best bet is to use boost::shared_ptr and boost::weak_ptr. Seehttp://www.boost.org/libs/smart_ptr/smart_ptr.htmformore 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
    > 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.
    , Sep 22, 2007
    #6
  7. wrote:
    > On Sep 19, 1:53 am, 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.
    Gianni Mariani, Sep 23, 2007
    #7
  8. James Kanze Guest

    On Sep 19, 1:05 am, wrote:
    > 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.

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, Sep 23, 2007
    #8
  9. werasm Guest

    wrote:


    > 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?


    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
    werasm, Sep 23, 2007
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Vijayaraghavan Kalyanapasupathy

    Smart Pointers and "new"

    Vijayaraghavan Kalyanapasupathy, Feb 24, 2004, in forum: C++
    Replies:
    2
    Views:
    373
    Jeff Flinn
    Feb 24, 2004
  2. MotoK
    Replies:
    59
    Views:
    1,791
    Keith Thompson
    Sep 15, 2006
  3. Matthias Kaeppler
    Replies:
    5
    Views:
    440
    Axter
    Sep 10, 2005
  4. n2xssvv g02gfr12930

    Smart pointers and member function pointers

    n2xssvv g02gfr12930, Nov 26, 2005, in forum: C++
    Replies:
    3
    Views:
    463
    n2xssvv g02gfr12930
    Nov 27, 2005
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    657
Loading...

Share This Page