Boost logo

Boost Users :

From: Alan M. Carroll (amc_at_[hidden])
Date: 2008-08-20 13:15:05


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 <boost/intrusive_ptr.hpp>

/** @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<self const*>(t)->_reference_count); }
    friend inline void intrusive_ptr_release(T const* t) { if (--(static_cast<self const*>(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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net