|
Boost : |
From: Greg Colvin (Gregory.Colvin_at_[hidden])
Date: 2003-02-22 19:19:24
The weather kept me at home today, so I had time to hack in
a new constructor for shared_ptr that keeps the count in a
header which is allocated along with the counted object.
Like intrusive_ptr, but intrusive in a different way. If
anyone has time to apply the patches and see if it is as
fast as it should be I would most grateful.
The new public constructor goes inside shared_ptr in
shared_ptr.hpp:
template<typename Y>
explicit shared_ptr(Y * p,const detail::counted_header_tag<Y>&)
: px(p), pn(detail::new_counted_base_in_object_header(p)) // Y must be complete
{
}
To make it easier to get the tags right I added a few
helper functions, which made me wish again for type-safe
variadic functions. They go in the boost namespace in
shared_ptr.hpp:
template<typename T>
inline shared_ptr<T> new_counted() {
detail::counted_header_tag<T> counted;
return shared_ptr<T>(new(counted) T(),counted);
}
template<typename T, typename P1>
inline shared_ptr<T> new_counted(const P1& p1) {
detail::counted_header_tag<T> counted;
return shared_ptr<T>(new(counted) T(p1),counted);
}
template<typename T, typename P1, typename P2>
inline shared_ptr<T> new_counted(const P1& p1,const P2& p2) {
detail::counted_header_tag<T> counted;
return shared_ptr<T>(new(counted) T(p1,p2),counted);
}
template<typename T, typename P1, typename P2, typename P3>
inline shared_ptr<T> new_counted(const P1& p1,const P2& p2,const P3& p3) {
detail::counted_header_tag<T> counted;
return shared_ptr<T>(new(counted) T(p1,p2,p3),counted);
}
// ... repeat above with more args until bored
The guts of the change go near the end of shared_count.hpp:
namespace boost {
namespace detail {
template<class P, class D> class counted_base_header_impl: public counted_base
{
private:
P ptr; // copy constructor must not throw
D del; // copy constructor must not throw
counted_base_header_impl(counted_base_header_impl const &);
counted_base_header_impl & operator= (counted_base_header_impl const &);
public:
// pre: initial_use_count <= initial_weak_count, d(p) must not throw
counted_base_header_impl(P p, D d, long initial_use_count, long initial_weak_count):
counted_base(initial_use_count, initial_weak_count), ptr(p), del(d)
{
}
virtual void destruct() // nothrow
{
}
virtual void dispose() // nothrow
{
del(ptr);
}
};
template<typename T> struct object_with_counted_header {
char header[sizeof(counted_base_header_impl<T*,checked_deleter<T> >)];
char object[sizeof(T)];
};
template<typename T> inline void* get_counted_object_header(T* p) {
return (char*)p - offsetof(object_with_counted_header<T>,object);
}
template<class T> struct checked_counted_header_deleter
{
typedef void result_type;
typedef T* argument_type;
void operator()(T* p)
{
typedef char type_must_be_complete[sizeof(T)];
::operator delete(get_counted_object_header(p));
}
};
template<typename T>
inline counted_base* new_counted_base_in_object_header(T* p) {
return new (get_counted_object_header(p))
counted_base_header_impl<T*,checked_counted_header_deleter<T> >
(p,checked_counted_header_deleter<T>(),1,1);
}
template<typename T> struct counted_header_tag {};
} // namespace detail
} // namespace boost
template <typename T>
inline void* operator new(size_t n,const boost::detail::counted_header_tag<T>&) {
assert(n == sizeof(T));
return (char*)::operator new(sizeof(boost::detail::object_with_counted_header<T>))
+ offsetof(boost::detail::object_with_counted_header<T>,object);
}
I haven't bothered with an array version yet, and have tested
only with GCC on Cygwin.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk