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: