Changed intrusive_ref_counter to follow CRTP design.

[SVN r85547]
This commit is contained in:
Andrey Semashev
2013-09-01 21:05:14 +00:00
parent a7d96b4762
commit 7b9354fcf3
4 changed files with 88 additions and 76 deletions

View File

@@ -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 <tt>use_count() == 0</tt>
*/
basic_intrusive_ref_counter() : m_ref_counter(0)
intrusive_ref_counter() BOOST_NOEXCEPT : m_ref_counter(0)
{
}
@@ -121,21 +122,16 @@ public:
*
* \post <tt>use_count() == 0</tt>
*/
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_

View File

@@ -25,7 +25,7 @@
and <STRONG>intrusive_ptr_release</STRONG> should be defined in the namespace
that corresponds to their parameter; otherwise, the definitions need to go in
namespace <STRONG>boost</STRONG>. The library provides a helper base class template
<STRONG><a href="intrusive_ref_counter.html">basic_intrusive_ref_counter</a></STRONG> which may
<STRONG><a href="intrusive_ref_counter.html">intrusive_ref_counter</a></STRONG> which may
help adding support for <STRONG>intrusive_ptr</STRONG> to user&apos;s types.</p>
<p>The class template is parameterized on <b>T</b>, the type of the object pointed
to. <STRONG>intrusive_ptr&lt;T&gt;</STRONG> can be implicitly converted to <STRONG>intrusive_ptr&lt;U&gt;</STRONG>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>basic_intrusive_ref_counter</title>
<title>intrusive_ref_counter</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body text="#000000" bgColor="#ffffff">
@@ -13,50 +13,51 @@
<A href="#Members">Members</A><br>
</p>
<h2><a name="Introduction">Introduction</a></h2>
<p>The <STRONG>basic_intrusive_ref_counter</STRONG> class template implements a reference counter for a defived
<p>The <STRONG>intrusive_ref_counter</STRONG> class template implements a reference counter for a derived
user&apos;s class that is intended to be used with <STRONG><a href="intrusive_ptr.html">intrusive_ptr</a></STRONG>.
The base class has associated <STRONG>intrusive_ptr_add_ref</STRONG> and <STRONG>intrusive_ptr_release</STRONG> functions
which modify the reference counter as needed and destroy the user's object when the counter drops to zero.</p>
<p>The class template is parameterized on <STRONG>CounterPolicyT</STRONG>, which is a policy that defines the nature of the reference counter.
<p>The class template is parameterized on <STRONG>DerivedT</STRONG> and <STRONG>CounterPolicyT</STRONG> parameters.
The first parameter is the user&apos;s class that derives from <STRONG>intrusive_ref_counter</STRONG>. This type
is needed in order to destroy the object correctly when there are no references to it left.</p>
<p>The second parameter is a policy that defines the nature of the reference counter.
Boost.SmartPtr provides two such policies: <STRONG>thread_unsafe_counter</STRONG> and <STRONG>thread_safe_counter</STRONG>. The former
instructs the <STRONG>basic_intrusive_ref_counter</STRONG> base class to use a counter only suitable for a single-threaded use.
instructs the <STRONG>intrusive_ref_counter</STRONG> 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 <STRONG>intrusive_ref_counter</STRONG> is provided, which is an alias for
<STRONG>basic_intrusive_ref_counter&lt;thread_safe_counter&gt;</STRONG>.</p>
threading is common, the default counter policy is <STRONG>thread_safe_counter</STRONG>.</p>
<h2><a name="Synopsis">Synopsis</a></h2>
<pre>namespace boost {
template&lt;class CounterPolicyT&gt; class basic_intrusive_ref_counter {
public:
<A href="#constructors" >basic_intrusive_ref_counter</A>();
<A href="#constructors" >basic_intrusive_ref_counter</A>(basic_intrusive_ref_counter const &amp; r);
virtual <A href="#destructor" >~basic_intrusive_ref_counter</A>();
basic_intrusive_ref_counter &amp; <A href="#assignment" >operator=</A>(basic_intrusive_ref_counter const &amp; r) noexcept;
unsigned int <a href="#use_count" >use_count</a>() const noexcept;
};
struct thread_unsafe_counter;
struct thread_safe_counter;
typedef basic_intrusive_ref_counter&lt;thread_safe_counter&gt; intrusive_ref_counter;
template&lt;class DerivedT, class CounterPolicyT = thread_safe_counter&gt;
class intrusive_ref_counter
{
public:
<A href="#constructors" >intrusive_ref_counter</A>() = noexcept;
<A href="#constructors" >intrusive_ref_counter</A>(intrusive_ref_counter const &amp; r) = noexcept;
intrusive_ref_counter &amp; <A href="#assignment" >operator=</A>(intrusive_ref_counter const &amp; r) noexcept;
unsigned int <a href="#use_count" >use_count</a>() const noexcept;
protected:
<A href="#destructor" >~intrusive_ref_counter</A>() = default;
};
}</pre>
<h2><a name="Members">Members</a></h2>
<h3><a name="constructors">constructors</a></h3>
<pre>basic_intrusive_ref_counter();</pre>
<pre>intrusive_ref_counter();</pre>
<blockquote>
<p><b>Postconditions:</b> <code>use_count() == 0</code>.</p>
<p><b>Throws:</b> nothing.</p>
<P><B>Notes:</B> The pointer to the constructed object is expected to be passed to <STRONG>intrusive_ptr</STRONG>
constructor, assignment operator or <STRONG>reset()</STRONG> method, which would increment the reference counter.</P>
</blockquote>
<pre>basic_intrusive_ref_counter(basic_intrusive_ref_counter const &amp;);</pre>
<pre>intrusive_ref_counter(intrusive_ref_counter const &amp;);</pre>
<blockquote>
<p><b>Postconditions:</b> <code>use_count() == 0</code>.</p>
<p><b>Throws:</b> nothing.</p>
@@ -64,12 +65,14 @@
constructor, assignment operator or <STRONG>reset()</STRONG> method, which would increment the reference counter.</P>
</blockquote>
<h3><a name="destructor">destructor</a></h3>
<pre>virtual ~basic_intrusive_ref_counter();</pre>
<pre>~intrusive_ref_counter();</pre>
<BLOCKQUOTE>
<p><b>Throws:</b> nothing.</p>
<P><B>Effects:</B> Destroys the counter object.</P>
<P><B>Notes:</B> The destructor is protected so that the object can only be destroyed through the <STRONG>DerivedT</STRONG> class.</P>
</BLOCKQUOTE>
<H3><a name="assignment">assignment</a></H3>
<pre>basic_intrusive_ref_counter &amp; operator=(basic_intrusive_ref_counter const &amp; r) noexcept;</pre>
<pre>intrusive_ref_counter &amp; operator=(intrusive_ref_counter const &amp; r) noexcept;</pre>
<BLOCKQUOTE>
<P><B>Effects:</B> Does nothing, reference counter is not modified.</P>
<P><B>Returns:</B> <code>*this</code>.</P>
@@ -83,7 +86,7 @@
</BLOCKQUOTE>
<hr>
<p>
$Date: 2013-08-31 23:37:43 +0400 (Sat, 31 Aug 2013) $</p>
$Date$</p>
<p>
<small>Copyright <20> 2013 Andrey Semashev. Distributed under the Boost Software License, Version
1.0. See accompanying file <A href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</A> or

View File

@@ -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();