Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2003-05-27 14:39:58


Chuck Messenger wrote:
>
> Suppose I have a cyclic dependency between A and B, which are
> implemented with the pimpl idiom:
>
> #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
> }
>
> OK, so we want to solve the problem that A and B keep eachother alive.
>
> I don't see how a weak_ptr can be used, without breaking the whole way
> I'm using A and B -- see get_A() and get_B().

[...]

> In general, the abstraction is: you have a group of intra-referential
> objects. When any of the group is constructed, they are all
> constructed (so that the master count is temporarily > 1), and the
> master count is
> reset to 1. When the master count goes to 0, the group is destructed.
> Hence, the group only remains alive as long as there are any external
> references (and as long as the intra-group references remain static).

In the situation you describe, A logically contains a B and B logically
contains an A, so A and B aren't independent; they actually form an AB
object. There is nothing to be gained from separating A and B as this
doesn't eliminate a dependency. If A and B are optional (but still tightly
coupled) parts of AB, the way I'd express this would probably be

class AB
{
    shared_ptr<A_impl> ai_;
    shared_ptr<B_impl> bi_;
};

There are several ways to allow A_impl and B_impl to communicate: store an
AB* pointer in each; pass a B_impl* to A_impl's methods that need it; keep a
B_impl* or a weak_ptr<B_impl> in A_impl.


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