At 08:33 AM 8/20/2008, you wrote:
I didn't mean a formal Boost review... just a "can we take a look at it" review.
Allright. I did a bit of cleanup and testing this morning and this is what I have.
Known issues:
* May not handle cross assignment of target object.
* No thread safety (not something I need, but should be thought about during Boostification)
# pragma once
// Copyright 2008 Network Geographics Inc.
// All rights reserved.
# include
/** @file
Extensions for Boost.instrusive_ptr.
*/
namespace boost
{
/** Helper template mixin for @c boost::intrusive_ptr.
To add support for @c boost::intrusive_ptr to class @c T, it should inherit from
@c reference_counter<T>. This will
- provide a reference count member
- force the reference count to initialize to zero
- define the add and release global functions required by @c intrusive_ptr
If this class is not inherited publically, then the class @c T must declare
the global functions as friends to permit them to cast @c T* to @c reference_counter<T>*.
This can be done with the following two lines, with either the @c self typedef
or the string "self" replaced by the actual name of class @c T.
@code
friend void boost::intrusive_ptr_add_ref(self const*);
friend void boost::intrusive_ptr_release(self const*);
@endcode
@note Due to changes in the C++ standard and design decisions in gcc,
it is no longer possible to declare a template parameter as a friend class.
(Basically, you can't use a typedef in a friend declaration and gcc treats
template parameters as typedefs).
@note You can use this with insulated (by name only) classes. The important
thing is to make sure that any class that uses an @c intrusive_ptr to a
by name only class has all of its constructors and destructors declared
in the header and defined in the implementation translation unit. If the
compiler generates any of those, it will not compile due to missing
functions or methods.
*/
template <typename T> class reference_counter
{
protected:
typedef reference_counter self; //!< Useful for self type reference
//! Default constructor.
reference_counter() : _reference_count(0) { }
/** Copy constructor.
@note Always initialize to zero. Ignore the source count.
This makes it nicer for clients who can now use the default
copy constructor.
*/
reference_counter(self const&) : _reference_count(0) { }
/** Assignment operator.
@note Prevent the count from being assigned.
*/
self& operator= (self const&) { return *this; }
/// Check for multiple references.
/// @return @c true if more than one smart pointer references the object, @c false otherwise.
bool is_shared() const { return _reference_count > 1; }
/// Check for a single reference (@c shared_ptr compatibility)
bool unique() const { return _reference_count <= 1; }
/// Number of references (@c shared_ptr compatibility)
long use_count() const { return _reference_count; }
mutable long _reference_count; //!< The reference count
//! Define the helper functions and give them access
//!@{
friend inline void intrusive_ptr_add_ref(T const* t) { ++(static_cast(t)->_reference_count); }
friend inline void intrusive_ptr_release(T const* t) { if (--(static_cast(t)->_reference_count) <= 0) delete t; }
//!@}
};
// forward declare
template < typename T > class intrusive_monitor;
/** Weak pointer for @c intrusive_ptr.
This object contains a reference to a target object.
An @c intrusive_ptr to that target object can be obtained from
this object. If the target object has been destructed, the
@c intrusive_ptr will be @c nil.
@note The target object class must provide support for this to work.
@see intrusive_monitor
*/
template < typename T >
class weak_intrusive_ptr
{
protected:
/// The structure allocated to watch the target object.
/// It exists only to hold a raw pointer to the target.
/// The pointer is reset to @c nil when the target is destructed.
struct monitor
: public reference_counter<monitor>
{
typedef monitor self; ///< Self reference type
typedef intrusive_ptr<self> handle; ///< Smart pointer type
/// Construct with target
monitor(T* target) : _target(target) {}
T* _target; ///< The target object.
};
typename monitor::handle _monitor; ///< Our reference to the monitor
friend class intrusive_monitor<T>;
private:
typedef weak_intrusive_ptr self; ///< Self reference type
public:
/** Default constructor.
A default constructed @c intrusive_weak_ptr acts as if
the target object has been destructed.
Use assignment to re-target.
*/
weak_intrusive_ptr() {}
/// Construct from raw pointer
weak_intrusive_ptr(T* target) { *this = target; }
/// Construct from intrusive pointer
weak_intrusive_ptr(intrusive_ptr<T> const& ptr) { *this = ptr.get(); }
/// Assign intrusive pointer
self& operator = (intrusive_ptr<T> const& ptr) { return *this = ptr.get(); }
/// Assign raw pointer
self& operator = (T* target)
{
intrusive_monitor<T>* im = static_cast< intrusive_monitor<T>* >(target);
if (im) {
// Subtle - if the monitor hasn't been initialized at all, create it.
// But! if it's there, do *not* set the target because the monitor is
// always initialized with a valid pointer. The monitor being present
// with a @c nil target means it's a dangling pointer and we need to stop digging.
if (!im->_intrusive_monitor)
im->_intrusive_monitor = new monitor(target);
_monitor = im->_intrusive_monitor;
}
return *this;
}
/** Get an @c intrusive_ptr to the target.
@return A valid smart pointer to the target object if it has not been destructed,
a @a nil smart pointer otherwise.
*/
intrusive_ptr<T> lock() const
{
return intrusive_ptr<T>(_monitor ? _monitor->_target : 0);
}
};
/** Helper template mixin for @c boost::weak_intrusive_ptr.
To add support for @c weak_intrusive_ptr to class @c T, it should inherit from
@c intrusive_monitor<T>. This will
- provide a reference count member
- force the reference count to initialize to zero
- define the add and release global functions required by @c intrusive_ptr
- create a monitor to support intrusive_weak_ptr
This class inherits from @c reference_counter and all requirements for that
are also requirements for this mixin. This adds the monitor for weak pointers
to the target object.
It is not necessary to explicitly initialize the monitor. If it is in the
default constructed state when a @c weak_intrusive_ptr is created, it will
initialized appropriately. In that case, the allocation cost of monitoring
isn't paid unless used.
Explicit intialization of the monitor, if desired, can be done either by use of
base class initialization or by use of the inherited @c init_intrusive_monitor
method. Which is appropriate depends on whether the target class uses member
initialization or has its own @c init method called from its various constructors.
@code
class A : public boost::intrusive_monitor<A>
{
// This will generate warning C4355 in Microsoft Visual Studio, which can be ignored.
A() : intrusive_monitor(this) { ... }
};
@endcode
or
@code
class A : public boost::intrusive_monitor<A>
{
A() { ... this->init(); ... }
void init() {
// ...
this->init_intrusive_monitor(this);
// ...
}
};
@endcode
*/
template < typename T >
class intrusive_monitor
: public reference_counter<T>
{
private:
typedef intrusive_monitor self; ///< Self reference type
protected:
typename weak_intrusive_ptr<T>::monitor::handle _intrusive_monitor; ///< Our reference to the monitor
public:
/** Default constructor.
The monitor is not allocated by this constructor, which means
that @c get_weak_intrusive_ptr will return a non-functional instance
until the monitor is initialized.
@see init_intrusive_monitor
*/
intrusive_monitor() {}
/// Construct with target to monitor.
intrusive_monitor(T* target) : _intrusive_monitor(new weak_intrusive_ptr<T>::monitor(target)) {}
/// Destructor.
~intrusive_monitor() { if (_intrusive_monitor) _intrusive_monitor->_target = 0; }
/// Copy constructor.
/// Don't copy monitor.
intrusive_monitor(self const& that) {}
/// Assignment.
/// Don't copy monitor.
self& operator = (self const& that) { return *this; }
protected:
/** Initialize the monitor.
This is intended for use by classes that need to have initialization
methods that are called from various constructors. This should only
be called if the default constructor for this mixin is used.
@return A reference to @c this.
*/
self& init_intrusive_monitor(T* target)
{
if (_intrusive_monitor)
_intrusive_monitor->_target = target;
else
_intrusive_monitor = new monitor(target);
return *this;
}
friend class weak_intrusive_ptr<T>;
};
} // namespace boost