From 7b9354fcf34919057950dfca11ff6280ffce2775 Mon Sep 17 00:00:00 2001
From: Andrey Semashev
Date: Sun, 1 Sep 2013 21:05:14 +0000
Subject: [PATCH] Changed intrusive_ref_counter to follow CRTP design.
[SVN r85547]
---
.../boost/smart_ptr/intrusive_ref_counter.hpp | 67 +++++++++----------
intrusive_ptr.html | 2 +-
intrusive_ref_counter.html | 55 ++++++++-------
test/intrusive_ref_counter_test.cpp | 40 ++++++-----
4 files changed, 88 insertions(+), 76 deletions(-)
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
- 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.
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;
+ };
}
- 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.
- 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.
- 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();