Boost logo

Boost :

From: Schoenborn, Oliver (Oliver.Schoenborn_at_[hidden])
Date: 2003-05-28 22:59:46


> -----Original Message-----
> From: Chuck Messenger [mailto:chuckm_at_[hidden]]
> Sent: Wednesday, May 28, 2003 2:35 PM
> To: boost_at_[hidden]
> Subject: [boost] Cyclic smart pointers (holy grail: the uber-pointer)
>
>
> Schoenborn, Oliver wrote:
> >>NoPtr lib -- noptrlib.sourceforge.net
> >>
> >>...I saw no mention of detecting dead cyclic object pools.
> >
> > Can you give me a short example of how NoPtr would even need to detect
that
> > to work correctly? I suspect that if you end up with cyclic object pool
you
> > are using NoPtr incorrectly (just like passing a pointer to an auto
variable
> > to a shared_ptr is incorrect use), but maybe an example will show me to
be
> > wrong.
> >
> > Oliver
>
> Here's my example (from an earlier thread):
>
> #include <boost/shared_ptr.hpp>
> #include <iostream>
>
> using namespace boost;
> using namespace std;
>
>
> struct B_impl;
>
> struct B {
> shared_ptr<B_impl> pimpl_;
> };
>
> struct A_impl {
> A_impl() { cout << "new A\n"; }
> ~A_impl() { cout << "del A\n"; }
> B b_;
> };
>
> struct A {
> shared_ptr<A_impl> pimpl_;
> B get_B() const { return pimpl_->b_; }
> };
>
> struct B_impl {
> B_impl() { cout << "new B\n"; }
> ~B_impl() { cout << "del B\n"; }
> A a_;
> };
>
> A get_A(const B& b) { return b.pimpl_->a_; }
> B get_B(const A& a) { return a.pimpl_->b_; }
>
> A construct_A() {
> A a;
> a.pimpl_.reset(new A_impl); // a refcount is 1
> B& b = a.pimpl_->b_;
> b.pimpl_.reset(new B_impl); // b refcount is 1
> b.pimpl_->a_ = a; // a refcount is 2
>
> return a;
> }
>
> int main() {
> {
> A a = construct_A();
> }
> // ex-a's refcount is still 1, so object doesn't die
> }

The above code does not make sense from a strict ownership point of view.
This is a quality (good or bad depending on what you are looking for) of
strict ownership: it forces you to be clear about who owns and for how long.
In the above code, you would have to decide whether A and B own their pimpl.

     struct B_impl;
     struct B {
         DynObj<B_impl> pimpl_;
     };

     struct A_impl {
         B b_;
     };
     struct A {
         DynObj<A_impl> pimpl_;
     };

     struct B_impl {
         A a_;
     };

     A construct_A() {
         A a;
         a.pimpl_.acquire(new A_impl); // a owns A_impl
         B& b = a.pimpl_().b_;
         b.pimpl_.acquire(new B_impl); // b owns B_impl
         b.pimpl_().a_ = a; // compile error, logic wrong
                            // for strict ownership
         return a;
     }

Indeed because A owns the pimpl_, the line before returning doesn't make
sense for strict ownership. Without knowing more about your problem, there
are two possibilities:
- You always have A owns A_impl owns B owns B_impl refs A (what your
original code seems to say), in this case B_impl contains an RRef<A> instead
of a DynObj<A> and everything works
- Your program can also have B owns B_impl owns A owns A_impl refs B, i.e.
in some cases you have (indirectly) B owns A, other times A owns B. This one
requires more thought, and strict ownership may not be the solution since
this says that the ownership can have two forms.

Oliver


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk