Opened 15 years ago
Closed 9 years ago
#1109 closed Feature Requests (fixed)
intrusive_ptr needs a helper base class
| Reported by: | Peter Dimov | Owned by: | Peter Dimov |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | smart_ptr |
| Version: | Severity: | Problem | |
| Keywords: | Cc: |
Description
http://lists.boost.org/Archives/boost/2006/04/103182.php http://lists.boost.org/Archives/boost/2006/04/103203.php http://lists.boost.org/Archives/boost/2006/04/103267.php http://lists.boost.org/Archives/boost/2006/04/103273.php
class counted_base
{
private:
mutable detail::atomic_count count_;
protected:
counted_base(): count_( 0 ) {}
virtual ~counted_base() {}
counted_base( counted_base const & ): count_( 0 ) {}
counted_base& operator=( counted_base const & ) { return *this; }
public:
inline friend void intrusive_ptr_add_ref( counted_base const * p )
{
++p->count_;
}
inline friend void intrusive_ptr_release( counted_base const * p )
{
if( --p->count_ == 0 ) delete p;
}
long use_count() const { return count_; }
};
Change History (10)
comment:1 by , 15 years ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:2 by , 14 years ago
| Milestone: | To Be Determined → Boost 1.37.0 |
|---|
comment:3 by , 14 years ago
| Milestone: | Boost 1.37.0 → To Be Determined |
|---|
comment:4 by , 12 years ago
| Status: | assigned → new |
|---|
comment:5 by , 11 years ago
follow-up: 7 comment:6 by , 11 years ago
What's the advantage of intrusive over shared when make_shared is used?
comment:7 by , 9 years ago
Replying to Olaf van der Spek <olafvdspek@…>:
What's the advantage of intrusive over shared when make_shared is used?
Olaf,
one important advantage is that the class does not need to be fully defined,
another advantage is that you can create intrusive_ptr anywhere, you don't have to pass it around in order to have it.
comment:8 by , 9 years ago
I would also template the type of count_ variable, sometimes there's no need for thread-safe counter, and using long would give some performance boost
comment:9 by , 9 years ago
I use this base class. It is inspired by boost.intrusive and uses the example reference counter from boost.atomic.
If you want, I can improve this a bit. I think, it should be possible to select atomic/nonatomic internal counter and some checking policy (again inspired by boost.atomic).
#ifndef INTRUSIVE_PTR_BASE_HOOK_H_INCLUDED
#define INTRUSIVE_PTR_BASE_HOOK_H_INCLUDED
#include <memory>
#include <utility>
#include <boost/assert.hpp>
#include <boost/atomic.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/parameter/binding.hpp>
#include <boost/parameter/name.hpp>
#include <boost/parameter/parameters.hpp>
namespace utils {
BOOST_PARAMETER_TEMPLATE_KEYWORD(deleter)
BOOST_PARAMETER_TEMPLATE_KEYWORD(count_type)
typedef boost::parameter::parameters<
boost::parameter::optional<tag::deleter>,
boost::parameter::optional<tag::count_type>
> intrusive_ptr_base_hook_signature;
template<typename Derived, typename ... Params>
class intrusive_ptr_base_hook
{
typedef typename intrusive_ptr_base_hook_signature::bind<Params...>::type args;
protected :
typedef Derived derived_type;
typedef typename boost::parameter::binding<
args, tag::deleter, std::default_delete<derived_type>
>::type deleter_type;
typedef typename boost::parameter::binding<
args, tag::count_type, unsigned
>::type count_type;
private:
struct Data
: public deleter_type
{
boost::atomic<count_type> count;
constexpr Data(count_type c, deleter_type const & d)
: deleter_type(d)
, count(c)
{}
} m_data;
protected :
constexpr intrusive_ptr_base_hook()
: m_data(0, deleter_type())
{}
intrusive_ptr_base_hook(intrusive_ptr_base_hook const &) = delete;
intrusive_ptr_base_hook & operator=(intrusive_ptr_base_hook const &) = delete;
~intrusive_ptr_base_hook() noexcept
{
BOOST_ASSERT(m_count.load(boost::memory_order::memory_order_relaxed) == 0);
}
public :
friend void intrusive_ptr_add_ref(
intrusive_ptr_base_hook const * p)
{
const_cast<intrusive_ptr_base_hook*>(p)
->m_data.count.fetch_add(1, boost::memory_order_relaxed);
}
friend void intrusive_ptr_release(
intrusive_ptr_base_hook const * pc)
{
intrusive_ptr_base_hook * p = const_cast<intrusive_ptr_base_hook*>(pc);
if(p->m_data.count.fetch_sub(1, boost::memory_order_release) == 1)
{
boost::atomic_thread_fence(boost::memory_order_acquire);
// call deleter hidden in m_data
p->m_data(static_cast<derived_type*>(p));
}
}
};
template<typename T, typename ... Args>
inline boost::intrusive_ptr<T> make_intrusive(Args && ... args)
{
return boost::intrusive_ptr<T>(new T(std::forward<Args>(args)...));
}
}//namespace utils
#endif//INTRUSIVE_PTR_BASE_HOOK_H_INCLUDED
comment:10 by , 9 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
There's boost/smart_ptr/intrusive_ref_counter.hpp now.

Virtual destructor is not necessary here: