Notbad
Notbad

Reputation: 6296

intrusive_ptr using a base class for ref count and include cycles hell

I'm using boost::intrusive_ptr as my reference counted smart pointer. I'm using something like this:

http://www.codeproject.com/KB/stl/boostsmartptr.aspx#intrusive_ptr%20-%20lightweight%20shared%20pointer

This seems a good idea, because it simplifies the declaration of a new Reference counted class, just inheriting from it. The problem comes with forward declarations. There are a lot of places where I want to use a pointer to a type not yet decladed in a class definiton and it is not possible, because the 2 methods that handle ref count need to know if the type inherits from CRefCounted or not.

If I try to include the dependencies before the declaration of the intrusive_ptr it is ok, but then, I get a lot of cyclic includes.

How would you handle this scenario?

Upvotes: 2

Views: 1183

Answers (2)

Timo
Timo

Reputation: 5176

I've been using a similar RefCounted base class a lot and I started wondering why do I never have this problem. And it's because I tend to hide implementation details in source files. Consider the following header file of class B:

//File: B.h
#include <boost/intrusive_ptr.hpp>

class A;

class B
{
public:
    B();
    ~B();
    boost::intrusive_ptr<A> foo();
    void foo2(const boost::intrusive_ptr<A> p);
    boost::intrusive_ptr<A> p;
};

It works, because even though it is using intrusive_ptr, it doesn't need to instantiate its constructor or destructor. Therefore it doesn't need to know anything about the class A.

The place where it needs to know about A is in the source file. (And also in places where foo/foo2 are called). B's constructor and destructor implicitly call intrusive_ptr< A>'s constructor/destructor, so A's definition must be available.

//File: B.cpp
#include "B.h"
#include "A.h" //Include header where A is defined.

B::B() { }
B::~B() { }

//Other member functions...

I don't know if this helps in your case, but it's something to think about. :)

Upvotes: 0

MartinStettner
MartinStettner

Reputation: 29174

I think you can solve this using templates functions for intrusive_ptr_add_ref and intrusive_ptr_release as follows:

namespace boost {
  template<class T> void intrusive_ptr_add_ref(T* p) { ++(p->references) }
  template<class T>void intrusive_ptr_release(T* p) { 
    if (--(p->references) == 0) 
      delete p 
  }
};

You'll also need to adapt the friend declarations in CRefCounted like

template class<T> friend void ::boost::intrusive_ptr_add_ref(T*);
template class<T> friend void ::boost::intrusive_ptr_release(T*);

Using these declarations, you can use intrusive_ptr on forward-declared classes like

class A;
class B {
  ::boost::intrusive_ptr<A> _myPtr;
};
class A : public CRefCounted {
};

This solution has the drawback (theoretically...), that you define a pair of add_ref/release functions for every subclass of CRefCounted, but I think that the compiler will choose to use inlining anyway, so this can be neglected.

Upvotes: 3

Related Questions