Major changes to shared_ptr and weak_ptr

[SVN r16314]
This commit is contained in:
Peter Dimov
2002-11-18 14:37:02 +00:00
parent 2314f20c4e
commit f6b7ff4b34
6 changed files with 2351 additions and 317 deletions

View File

@ -40,7 +40,7 @@ namespace boost
// The standard library that comes with Borland C++ 5.5.1 // The standard library that comes with Borland C++ 5.5.1
// defines std::exception and its members as having C calling // defines std::exception and its members as having C calling
// convention (-pc). When the definition of use_count_is_zero // convention (-pc). When the definition of bad_weak_ptr
// is compiled with -ps, the compiler issues an error. // is compiled with -ps, the compiler issues an error.
// Hence, the temporary #pragma option -pc below. The version // Hence, the temporary #pragma option -pc below. The version
// check is deliberately conservative. // check is deliberately conservative.
@ -49,13 +49,13 @@ namespace boost
# pragma option push -pc # pragma option push -pc
#endif #endif
class use_count_is_zero: public std::exception class bad_weak_ptr: public std::exception
{ {
public: public:
virtual char const * what() const throw() virtual char const * what() const throw()
{ {
return "boost::use_count_is_zero"; return "boost::bad_weak_ptr";
} }
}; };
@ -63,6 +63,9 @@ public:
# pragma option pop # pragma option pop
#endif #endif
namespace detail
{
class counted_base class counted_base
{ {
private: private:
@ -109,50 +112,36 @@ public:
void add_ref() void add_ref()
{ {
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutex_type::scoped_lock lock(mtx_); mutex_type::scoped_lock lock(mtx_);
#endif #endif
if(use_count_ == 0 && weak_count_ != 0) boost::throw_exception(boost::use_count_is_zero()); if(use_count_ == 0 && weak_count_ != 0) boost::throw_exception(boost::bad_weak_ptr());
++use_count_; ++use_count_;
++weak_count_; ++weak_count_;
} }
void release() // nothrow void release() // nothrow
{ {
long new_use_count;
long new_weak_count = 0;
{ {
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutex_type::scoped_lock lock(mtx_); mutex_type::scoped_lock lock(mtx_);
#endif #endif
new_use_count = --use_count_; long new_use_count = --use_count_;
if(new_use_count != 0) if(new_use_count != 0)
{ {
new_weak_count = --weak_count_; --weak_count_;
return;
} }
} }
if(new_use_count == 0) dispose();
{ weak_release();
dispose();
#ifdef BOOST_HAS_THREADS
mutex_type::scoped_lock lock(mtx_);
#endif
new_weak_count = --weak_count_;
}
if(new_weak_count == 0)
{
destruct();
}
} }
void weak_add_ref() // nothrow void weak_add_ref() // nothrow
{ {
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutex_type::scoped_lock lock(mtx_); mutex_type::scoped_lock lock(mtx_);
#endif #endif
++weak_count_; ++weak_count_;
@ -163,7 +152,7 @@ public:
long new_weak_count; long new_weak_count;
{ {
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutex_type::scoped_lock lock(mtx_); mutex_type::scoped_lock lock(mtx_);
#endif #endif
new_weak_count = --weak_count_; new_weak_count = --weak_count_;
@ -177,7 +166,7 @@ public:
long use_count() const // nothrow long use_count() const // nothrow
{ {
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutex_type::scoped_lock lock(mtx_); mutex_type::scoped_lock lock(mtx_);
#endif #endif
return use_count_; return use_count_;
@ -193,29 +182,16 @@ private:
long use_count_; long use_count_;
long weak_count_; long weak_count_;
#ifdef BOOST_HAS_THREADS #if defined(BOOST_HAS_THREADS)
mutable mutex_type mtx_; mutable mutex_type mtx_;
#endif #endif
}; };
inline void intrusive_ptr_add_ref(counted_base * p)
{
p->add_ref();
}
inline void intrusive_ptr_release(counted_base * p)
{
p->release();
}
namespace detail
{
// //
// Borland's Codeguard trips up over the -Vx- option here: // Borland's Codeguard trips up over the -Vx- option here:
// //
#ifdef __CODEGUARD__ #ifdef __CODEGUARD__
#pragma option push -Vx- # pragma option push -Vx-
#endif #endif
template<class P, class D> class counted_base_impl: public counted_base template<class P, class D> class counted_base_impl: public counted_base
@ -273,16 +249,11 @@ private:
public: public:
shared_count(): pi_(new counted_base(1, 1)) shared_count(): pi_(0) // (new counted_base(1, 1))
{ {
} }
explicit shared_count(counted_base * pi): pi_(pi) // never throws template<class P, class D> shared_count(P p, D d): pi_(0)
{
pi_->add_ref();
}
template<class P, class D> shared_count(P p, D d, void const * = 0): pi_(0)
{ {
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
@ -309,11 +280,6 @@ public:
#endif #endif
} }
template<class P, class D> shared_count(P, D, counted_base * pi): pi_(pi)
{
pi_->add_ref();
}
#ifndef BOOST_NO_AUTO_PTR #ifndef BOOST_NO_AUTO_PTR
// auto_ptr<Y> is special cased to provide the strong guarantee // auto_ptr<Y> is special cased to provide the strong guarantee
@ -328,21 +294,21 @@ public:
~shared_count() // nothrow ~shared_count() // nothrow
{ {
pi_->release(); if(pi_ != 0) pi_->release();
} }
shared_count(shared_count const & r): pi_(r.pi_) // nothrow shared_count(shared_count const & r): pi_(r.pi_) // nothrow
{ {
pi_->add_ref(); if(pi_ != 0) pi_->add_ref();
} }
explicit shared_count(weak_count const & r); // throws use_count_is_zero when r.use_count() == 0 explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
shared_count & operator= (shared_count const & r) // nothrow shared_count & operator= (shared_count const & r) // nothrow
{ {
counted_base * tmp = r.pi_; counted_base * tmp = r.pi_;
tmp->add_ref(); if(tmp != 0) tmp->add_ref();
pi_->release(); if(pi_ != 0) pi_->release();
pi_ = tmp; pi_ = tmp;
return *this; return *this;
@ -357,12 +323,12 @@ public:
long use_count() const // nothrow long use_count() const // nothrow
{ {
return pi_->use_count(); return pi_ != 0? pi_->use_count(): 42; // '42' is an example of 'unspecified'
} }
bool unique() const // nothrow bool unique() const // nothrow
{ {
return pi_->use_count() == 1; return use_count() == 1;
} }
friend inline bool operator==(shared_count const & a, shared_count const & b) friend inline bool operator==(shared_count const & a, shared_count const & b)
@ -377,7 +343,7 @@ public:
}; };
#ifdef __CODEGUARD__ #ifdef __CODEGUARD__
#pragma option pop # pragma option pop
#endif #endif
@ -391,30 +357,30 @@ private:
public: public:
weak_count(): pi_(new counted_base(0, 1)) // can throw weak_count(): pi_(0) // nothrow // (new counted_base(0, 1)) // can throw
{ {
} }
weak_count(shared_count const & r): pi_(r.pi_) // nothrow weak_count(shared_count const & r): pi_(r.pi_) // nothrow
{ {
pi_->weak_add_ref(); if(pi_ != 0) pi_->weak_add_ref();
} }
weak_count(weak_count const & r): pi_(r.pi_) // nothrow weak_count(weak_count const & r): pi_(r.pi_) // nothrow
{ {
pi_->weak_add_ref(); if(pi_ != 0) pi_->weak_add_ref();
} }
~weak_count() // nothrow ~weak_count() // nothrow
{ {
pi_->weak_release(); if(pi_ != 0) pi_->weak_release();
} }
weak_count & operator= (shared_count const & r) // nothrow weak_count & operator= (shared_count const & r) // nothrow
{ {
counted_base * tmp = r.pi_; counted_base * tmp = r.pi_;
tmp->weak_add_ref(); if(tmp != 0) tmp->weak_add_ref();
pi_->weak_release(); if(pi_ != 0) pi_->weak_release();
pi_ = tmp; pi_ = tmp;
return *this; return *this;
@ -423,8 +389,8 @@ public:
weak_count & operator= (weak_count const & r) // nothrow weak_count & operator= (weak_count const & r) // nothrow
{ {
counted_base * tmp = r.pi_; counted_base * tmp = r.pi_;
tmp->weak_add_ref(); if(tmp != 0) tmp->weak_add_ref();
pi_->weak_release(); if(pi_ != 0) pi_->weak_release();
pi_ = tmp; pi_ = tmp;
return *this; return *this;
@ -439,7 +405,7 @@ public:
long use_count() const // nothrow long use_count() const // nothrow
{ {
return pi_->use_count(); return pi_ != 0? pi_->use_count(): 804; // '804' is an example of 'unspecified'
} }
friend inline bool operator==(weak_count const & a, weak_count const & b) friend inline bool operator==(weak_count const & a, weak_count const & b)
@ -455,7 +421,7 @@ public:
inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
{ {
pi_->add_ref(); if(pi_ != 0) pi_->add_ref();
} }
} // namespace detail } // namespace detail

View File

@ -0,0 +1,51 @@
#ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
#define BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
//
// enable_shared_from_this.hpp
//
// Copyright (c) 2002 Peter Dimov
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html
//
#include <boost/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
namespace boost
{
template<class T> class enable_shared_from_this
{
public:
shared_ptr<T> shared_from_this()
{
return shared_ptr<T>(weak_this);
}
shared_ptr<T const> shared_from_this() const
{
return shared_ptr<T const>(weak_this);
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
template<class Y> friend class shared_ptr;
#endif
weak_ptr<T> weak_this;
};
} // namespace boost
#endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED

View File

@ -76,8 +76,14 @@ template<> struct shared_ptr_traits<void const>
// is destroyed or reset. // is destroyed or reset.
// //
#if defined(BOOST_SP_ENABLE_CONSTRUCTOR_HOOK)
void shared_ptr_constructor_hook(void * p);
#endif
template<class T> class weak_ptr; template<class T> class weak_ptr;
template<class T> class intrusive_ptr; template<class T> class enable_shared_from_this;
template<class T> class shared_ptr template<class T> class shared_ptr
{ {
@ -87,18 +93,36 @@ private:
// typedef checked_deleter<T> deleter; // typedef checked_deleter<T> deleter;
typedef shared_ptr<T> this_type; typedef shared_ptr<T> this_type;
// enable_shared_from_this support
template<class Y> void sp_enable_shared_from_this(boost::enable_shared_from_this<Y> * q)
{
q->weak_this = *this;
}
void sp_enable_shared_from_this(void *)
{
}
public: public:
typedef T element_type; typedef T element_type;
typedef T value_type; typedef T value_type;
typedef T * pointer;
typedef typename detail::shared_ptr_traits<T>::reference reference;
shared_ptr(): px(0), pn() shared_ptr(): px(0), pn()
{ {
} }
template<class Y> template<class Y>
explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter<Y>(), p) // Y must be complete explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter<Y>()) // Y must be complete
{ {
sp_enable_shared_from_this(p);
#if defined(BOOST_SP_ENABLE_CONSTRUCTOR_HOOK)
shared_ptr_constructor_hook(p);
#endif
} }
// //
@ -109,6 +133,7 @@ public:
template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d) template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d)
{ {
sp_enable_shared_from_this(p);
} }
// generated copy constructor, assignment, destructor are fine // generated copy constructor, assignment, destructor are fine
@ -123,11 +148,6 @@ public:
{ {
} }
template<class Y>
shared_ptr(intrusive_ptr<Y> const & r): px(r.get()), pn(r.get()) // never throws
{
}
template<class Y> template<class Y>
shared_ptr(shared_ptr<Y> const & r, detail::static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn) shared_ptr(shared_ptr<Y> const & r, detail::static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
{ {
@ -154,8 +174,11 @@ public:
#ifndef BOOST_NO_AUTO_PTR #ifndef BOOST_NO_AUTO_PTR
template<class Y> template<class Y>
explicit shared_ptr(std::auto_ptr<Y> & r): px(r.get()), pn(r) explicit shared_ptr(std::auto_ptr<Y> & r): px(r.get()), pn()
{ {
Y * tmp = r.get();
pn = detail::shared_count(r);
sp_enable_shared_from_this(tmp);
} }
#endif #endif
@ -199,7 +222,7 @@ public:
this_type(p, d).swap(*this); this_type(p, d).swap(*this);
} }
typename detail::shared_ptr_traits<T>::reference operator* () const // never throws reference operator* () const // never throws
{ {
BOOST_ASSERT(px != 0); BOOST_ASSERT(px != 0);
return *px; return *px;
@ -246,6 +269,11 @@ public:
pn.swap(other.pn); pn.swap(other.pn);
} }
bool less(this_type const & rhs) const // implementation detail, never throws
{
return pn < rhs.pn;
}
// Tasteless as this may seem, making all members public allows member templates // Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston) // to work in the absence of member template friends. (Matthew Langston)
@ -287,7 +315,7 @@ template<class T> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<T>
template<class T> inline bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b) template<class T> inline bool operator<(shared_ptr<T> const & a, shared_ptr<T> const & b)
{ {
return std::less<T*>()(a.get(), b.get()); return a.less(b);
} }
template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b) template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
@ -295,6 +323,18 @@ template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
a.swap(b); a.swap(b);
} }
template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r)
{
return shared_ptr<T>(r, detail::static_cast_tag());
}
template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r)
{
return shared_ptr<T>(r, detail::dynamic_cast_tag());
}
// shared_*_cast names are deprecated. Use *_pointer_cast instead.
template<class T, class U> shared_ptr<T> shared_static_cast(shared_ptr<U> const & r) template<class T, class U> shared_ptr<T> shared_static_cast(shared_ptr<U> const & r)
{ {
return shared_ptr<T>(r, detail::static_cast_tag()); return shared_ptr<T>(r, detail::static_cast_tag());
@ -323,28 +363,6 @@ template<class T> inline T * get_pointer(shared_ptr<T> const & p)
return p.get(); return p.get();
} }
// shared_from_this() creates a shared_ptr from a raw pointer (usually 'this')
namespace detail
{
inline void sp_assert_counted_base(boost::counted_base const *)
{
}
template<class T> inline T * sp_remove_const(T const * p)
{
return const_cast<T *>(p);
}
} // namespace detail
template<class T> shared_ptr<T> shared_from_this(T * p)
{
detail::sp_assert_counted_base(p);
return shared_ptr<T>(detail::sp_remove_const(p));
}
} // namespace boost } // namespace boost
#ifdef BOOST_MSVC #ifdef BOOST_MSVC

View File

@ -76,11 +76,6 @@ public:
this_type().swap(*this); this_type().swap(*this);
} }
T * get() const // never throws; deprecated, removal pending, don't use
{
return pn.use_count() == 0? 0: px;
}
long use_count() const // never throws long use_count() const // never throws
{ {
return pn.use_count(); return pn.use_count();
@ -119,27 +114,6 @@ private:
}; // weak_ptr }; // weak_ptr
template<class T, class U> inline bool operator==(weak_ptr<T> const & a, weak_ptr<U> const & b)
{
return a.get() == b.get();
}
template<class T, class U> inline bool operator!=(weak_ptr<T> const & a, weak_ptr<U> const & b)
{
return a.get() != b.get();
}
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
// Resolve the ambiguity between our op!= and the one in rel_ops
template<class T> inline bool operator!=(weak_ptr<T> const & a, weak_ptr<T> const & b)
{
return a.get() != b.get();
}
#endif
template<class T> inline bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b) template<class T> inline bool operator<(weak_ptr<T> const & a, weak_ptr<T> const & b)
{ {
return a.less(b); return a.less(b);
@ -152,6 +126,8 @@ template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b)
template<class T> shared_ptr<T> make_shared(weak_ptr<T> const & r) // never throws template<class T> shared_ptr<T> make_shared(weak_ptr<T> const & r) // never throws
{ {
#if defined(BOOST_HAS_THREADS)
// optimization: avoid throw overhead // optimization: avoid throw overhead
if(r.use_count() == 0) if(r.use_count() == 0)
{ {
@ -162,15 +138,20 @@ template<class T> shared_ptr<T> make_shared(weak_ptr<T> const & r) // never thro
{ {
return shared_ptr<T>(r); return shared_ptr<T>(r);
} }
catch(use_count_is_zero const &) catch(bad_weak_ptr const &)
{ {
// Q: how can we get here?
// A: another thread may have invalidated r after the use_count test above.
return shared_ptr<T>(); return shared_ptr<T>();
} }
}
// Note: there is no get_pointer overload for weak_ptr. #else
// This is intentional. Even get() will disappear in a
// future release; these accessors are too error-prone. // optimization: avoid try/catch overhead when single threaded
return r.use_count() == 0? shared_ptr<T>(): shared_ptr<T>(r);
#endif
}
} // namespace boost } // namespace boost

File diff suppressed because it is too large Load Diff

View File

@ -24,11 +24,6 @@
#include <iostream> #include <iostream>
#include <set> #include <set>
bool boost_error(char const *, char const *, char const *, long)
{
return true; // fail with assert()
}
class Incomplete; class Incomplete;
Incomplete * get_ptr( boost::shared_ptr<Incomplete>& incomplete ) Incomplete * get_ptr( boost::shared_ptr<Incomplete>& incomplete )
@ -164,7 +159,6 @@ void test()
cp.reset(); cp.reset();
BOOST_TEST( cp2.use_count() == 2 ); BOOST_TEST( cp2.use_count() == 2 );
BOOST_TEST( cp3.use_count() == 2 ); BOOST_TEST( cp3.use_count() == 2 );
BOOST_TEST( cp.use_count() == 1 );
cp.reset( new int ); cp.reset( new int );
*cp = 98765; *cp = 98765;
BOOST_TEST( *cp == 98765 ); BOOST_TEST( *cp == 98765 );