diff --git a/include/boost/smart_ptr/intrusive_ref_counter.hpp b/include/boost/smart_ptr/intrusive_ref_counter.hpp index 53aeee9..8714153 100644 --- a/include/boost/smart_ptr/intrusive_ref_counter.hpp +++ b/include/boost/smart_ptr/intrusive_ref_counter.hpp @@ -27,9 +27,9 @@ namespace boost { namespace sp_adl_block { /*! - * \brief Thread unsafe reference counter policy for \c basic_intrusive_ref_counter + * \brief Thread unsafe reference counter policy for \c intrusive_ref_counter * - * The policy instructs the \c basic_intrusive_ref_counter base class to implement + * The policy instructs the \c intrusive_ref_counter base class to implement * a reference counter suitable for single threaded use only. Pointers to the same * object with this kind of reference counter must not be used by different threads. */ @@ -54,9 +54,9 @@ struct thread_unsafe_counter }; /*! - * \brief Thread safe reference counter policy for \c basic_intrusive_ref_counter + * \brief Thread safe reference counter policy for \c intrusive_ref_counter * - * The policy instructs the \c basic_intrusive_ref_counter base class to implement + * The policy instructs the \c intrusive_ref_counter base class to implement * a thread-safe reference counter, if the target platform supports multithreading. */ struct thread_safe_counter @@ -79,26 +79,27 @@ struct thread_safe_counter } }; -template< typename CounterPolicyT > -class basic_intrusive_ref_counter; +template< typename DerivedT, typename CounterPolicyT = thread_safe_counter > +class intrusive_ref_counter; -template< typename CounterPolicyT > -void intrusive_ptr_add_ref(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT; -template< typename CounterPolicyT > -void intrusive_ptr_release(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT; +template< typename DerivedT, typename CounterPolicyT > +void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT; +template< typename DerivedT, typename CounterPolicyT > +void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT; /*! * \brief A reference counter base class * * This base class can be used with user-defined classes to add support - * for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT - * and a virtual destructor, which makes the derived class polymorphic. + * for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT. * Upon releasing the last \c intrusive_ptr referencing the object - * derived from the \c basic_intrusive_ref_counter class, operator \c delete + * derived from the \c intrusive_ref_counter class, operator \c delete * is automatically called on the pointer to the object. + * + * The other template parameter, \c DerivedT, is the user's class that derives from \c intrusive_ref_counter. */ -template< typename CounterPolicyT > -class basic_intrusive_ref_counter +template< typename DerivedT, typename CounterPolicyT > +class intrusive_ref_counter { private: //! Reference counter type @@ -112,7 +113,7 @@ public: * * \post use_count() == 0 */ - basic_intrusive_ref_counter() : m_ref_counter(0) + intrusive_ref_counter() BOOST_NOEXCEPT : m_ref_counter(0) { } @@ -121,21 +122,16 @@ public: * * \post use_count() == 0 */ - basic_intrusive_ref_counter(basic_intrusive_ref_counter const&) : m_ref_counter(0) + intrusive_ref_counter(intrusive_ref_counter const&) BOOST_NOEXCEPT : m_ref_counter(0) { } - /*! - * Virtual destructor - */ - virtual ~basic_intrusive_ref_counter() {} - /*! * Assignment * * \post The reference counter is not modified after assignment */ - basic_intrusive_ref_counter& operator= (basic_intrusive_ref_counter const&) BOOST_NOEXCEPT { return *this; } + intrusive_ref_counter& operator= (intrusive_ref_counter const&) BOOST_NOEXCEPT { return *this; } /*! * \return The reference counter @@ -145,32 +141,35 @@ public: return CounterPolicyT::load(m_ref_counter); } - friend void intrusive_ptr_add_ref< CounterPolicyT >(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT; - friend void intrusive_ptr_release< CounterPolicyT >(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT; +protected: + /*! + * Destructor + */ + BOOST_DEFAULTED_FUNCTION(~intrusive_ref_counter(), {}) + + friend void intrusive_ptr_add_ref< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT; + friend void intrusive_ptr_release< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT; }; -template< typename CounterPolicyT > -inline void intrusive_ptr_add_ref(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT +template< typename DerivedT, typename CounterPolicyT > +inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT { CounterPolicyT::increment(p->m_ref_counter); } -template< typename CounterPolicyT > -inline void intrusive_ptr_release(const basic_intrusive_ref_counter< CounterPolicyT >* p) BOOST_NOEXCEPT +template< typename DerivedT, typename CounterPolicyT > +inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT { if (CounterPolicyT::decrement(p->m_ref_counter) == 0) - delete p; + delete static_cast< const DerivedT* >(p); } } // namespace sp_adl_block -using sp_adl_block::basic_intrusive_ref_counter; +using sp_adl_block::intrusive_ref_counter; using sp_adl_block::thread_unsafe_counter; using sp_adl_block::thread_safe_counter; -//! Convenience typedef for the default reference counter type -typedef basic_intrusive_ref_counter< thread_safe_counter > intrusive_ref_counter; - } // namespace boost #endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_ diff --git a/intrusive_ptr.html b/intrusive_ptr.html index c37a5b2..562d27a 100644 --- a/intrusive_ptr.html +++ b/intrusive_ptr.html @@ -25,7 +25,7 @@ and intrusive_ptr_release should be defined in the namespace that corresponds to their parameter; otherwise, the definitions need to go in namespace boost. The library provides a helper base class template - basic_intrusive_ref_counter which may + intrusive_ref_counter which may help adding support for intrusive_ptr to user's types.

The class template is parameterized on T, the type of the object pointed to. intrusive_ptr<T> can be implicitly converted to intrusive_ptr<U> diff --git a/intrusive_ref_counter.html b/intrusive_ref_counter.html index 30be3af..72a46e0 100644 --- a/intrusive_ref_counter.html +++ b/intrusive_ref_counter.html @@ -1,7 +1,7 @@ - basic_intrusive_ref_counter + intrusive_ref_counter @@ -13,50 +13,51 @@ Members

Introduction

-

The basic_intrusive_ref_counter class template implements a reference counter for a defived +

The intrusive_ref_counter class template implements a reference counter for a derived user's class that is intended to be used with intrusive_ptr. The base class has associated intrusive_ptr_add_ref and intrusive_ptr_release functions which modify the reference counter as needed and destroy the user's object when the counter drops to zero.

-

The class template is parameterized on CounterPolicyT, which is a policy that defines the nature of the reference counter. +

The class template is parameterized on DerivedT and CounterPolicyT parameters. + The first parameter is the user's class that derives from intrusive_ref_counter. This type + is needed in order to destroy the object correctly when there are no references to it left.

+

The second parameter is a policy that defines the nature of the reference counter. Boost.SmartPtr provides two such policies: thread_unsafe_counter and thread_safe_counter. The former - instructs the basic_intrusive_ref_counter base class to use a counter only suitable for a single-threaded use. + instructs the intrusive_ref_counter base class to use a counter only suitable for a single-threaded use. Pointers to a single object that uses this kind of reference counter must not be used in different threads. The latter policy makes the reference counter thread-safe, unless the target platform doesn't support threading. Since in modern systems support for - threading is common, a shorthand intrusive_ref_counter is provided, which is an alias for - basic_intrusive_ref_counter<thread_safe_counter>.

+ threading is common, the default counter policy is thread_safe_counter.

Synopsis

namespace boost {
 
-  template<class CounterPolicyT> class basic_intrusive_ref_counter {
-
-    public:
-
-      basic_intrusive_ref_counter();
-      basic_intrusive_ref_counter(basic_intrusive_ref_counter const & r);
-
-      virtual ~basic_intrusive_ref_counter();
-
-      basic_intrusive_ref_counter & operator=(basic_intrusive_ref_counter const & r) noexcept;
-
-      unsigned int use_count() const noexcept;
-  };
-
   struct thread_unsafe_counter;
   struct thread_safe_counter;
 
-  typedef basic_intrusive_ref_counter<thread_safe_counter> intrusive_ref_counter;
+  template<class DerivedT, class CounterPolicyT = thread_safe_counter>
+  class intrusive_ref_counter
+  {
+  public:
+      intrusive_ref_counter() = noexcept;
+      intrusive_ref_counter(intrusive_ref_counter const & r) = noexcept;
+
+      intrusive_ref_counter & operator=(intrusive_ref_counter const & r) noexcept;
+
+      unsigned int use_count() const noexcept;
+
+  protected:
+      ~intrusive_ref_counter() = default;
+  };
 
 }

Members

constructors

-
basic_intrusive_ref_counter();
+
intrusive_ref_counter();

Postconditions: use_count() == 0.

Throws: nothing.

Notes: The pointer to the constructed object is expected to be passed to intrusive_ptr constructor, assignment operator or reset() method, which would increment the reference counter.

-
basic_intrusive_ref_counter(basic_intrusive_ref_counter const &);
+
intrusive_ref_counter(intrusive_ref_counter const &);

Postconditions: use_count() == 0.

Throws: nothing.

@@ -64,12 +65,14 @@ constructor, assignment operator or reset() method, which would increment the reference counter.

destructor

-
virtual ~basic_intrusive_ref_counter();
+
~intrusive_ref_counter();
+

Throws: nothing.

Effects: Destroys the counter object.

+

Notes: The destructor is protected so that the object can only be destroyed through the DerivedT class.

assignment

-
basic_intrusive_ref_counter & operator=(basic_intrusive_ref_counter const & r) noexcept;
+
intrusive_ref_counter & operator=(intrusive_ref_counter const & r) noexcept;

Effects: Does nothing, reference counter is not modified.

Returns: *this.

@@ -83,7 +86,7 @@

- $Date: 2013-08-31 23:37:43 +0400 (Sat, 31 Aug 2013) $

+ $Date$

Copyright © 2013 Andrey Semashev. Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or diff --git a/test/intrusive_ref_counter_test.cpp b/test/intrusive_ref_counter_test.cpp index 4f2ab88..53d0bd3 100644 --- a/test/intrusive_ref_counter_test.cpp +++ b/test/intrusive_ref_counter_test.cpp @@ -38,7 +38,7 @@ namespace N1 { class my_class : - public boost::intrusive_ref_counter + public boost::intrusive_ref_counter< my_class > { public: static unsigned int destructor_count; @@ -56,7 +56,7 @@ unsigned int my_class::destructor_count = 0; namespace N2 { class my_class : - public boost::basic_intrusive_ref_counter< boost::thread_unsafe_counter > + public boost::intrusive_ref_counter< my_class, boost::thread_unsafe_counter > { public: static unsigned int destructor_count; @@ -73,17 +73,18 @@ unsigned int my_class::destructor_count = 0; namespace N3 { -struct X : - public virtual boost::intrusive_ref_counter +struct root : + public boost::intrusive_ref_counter< root > { + virtual ~root() {} }; } // namespace N3 namespace N4 { -struct Y : - public virtual boost::intrusive_ref_counter +struct X : + public virtual N3::root { }; @@ -91,9 +92,18 @@ struct Y : namespace N5 { +struct Y : + public virtual N3::root +{ +}; + +} // namespace N5 + +namespace N6 { + struct Z : - public N3::X, - public N4::Y + public N4::X, + public N5::Y { static unsigned int destructor_count; @@ -105,7 +115,7 @@ struct Z : unsigned int Z::destructor_count = 0; -} // namespace N5 +} // namespace N6 int main() @@ -130,16 +140,16 @@ int main() // The test checks that destroying through the base class works { - boost::intrusive_ptr< N5::Z > p1 = new N5::Z(); + boost::intrusive_ptr< N6::Z > p1 = new N6::Z(); BOOST_TEST(p1->use_count() == 1); - BOOST_TEST(N5::Z::destructor_count == 0); - boost::intrusive_ptr< boost::intrusive_ref_counter > p2 = p1; + BOOST_TEST(N6::Z::destructor_count == 0); + boost::intrusive_ptr< N3::root > p2 = p1; BOOST_TEST(p1->use_count() == 2); - BOOST_TEST(N5::Z::destructor_count == 0); + BOOST_TEST(N6::Z::destructor_count == 0); p1 = NULL; - BOOST_TEST(N5::Z::destructor_count == 0); + BOOST_TEST(N6::Z::destructor_count == 0); p2 = NULL; - BOOST_TEST(N5::Z::destructor_count == 1); + BOOST_TEST(N6::Z::destructor_count == 1); } return boost::report_errors();