forked from boostorg/smart_ptr
Major changes to shared_ptr and weak_ptr
[SVN r16314]
This commit is contained in:
@ -40,7 +40,7 @@ namespace boost
|
||||
|
||||
// The standard library that comes with Borland C++ 5.5.1
|
||||
// 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.
|
||||
// Hence, the temporary #pragma option -pc below. The version
|
||||
// check is deliberately conservative.
|
||||
@ -49,13 +49,13 @@ namespace boost
|
||||
# pragma option push -pc
|
||||
#endif
|
||||
|
||||
class use_count_is_zero: public std::exception
|
||||
class bad_weak_ptr: public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
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
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class counted_base
|
||||
{
|
||||
private:
|
||||
@ -109,50 +112,36 @@ public:
|
||||
|
||||
void add_ref()
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#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_;
|
||||
++weak_count_;
|
||||
}
|
||||
|
||||
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_);
|
||||
#endif
|
||||
new_use_count = --use_count_;
|
||||
long new_use_count = --use_count_;
|
||||
|
||||
if(new_use_count != 0)
|
||||
{
|
||||
new_weak_count = --weak_count_;
|
||||
--weak_count_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(new_use_count == 0)
|
||||
{
|
||||
dispose();
|
||||
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
new_weak_count = --weak_count_;
|
||||
}
|
||||
|
||||
if(new_weak_count == 0)
|
||||
{
|
||||
destruct();
|
||||
}
|
||||
dispose();
|
||||
weak_release();
|
||||
}
|
||||
|
||||
void weak_add_ref() // nothrow
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
++weak_count_;
|
||||
@ -163,7 +152,7 @@ public:
|
||||
long new_weak_count;
|
||||
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
new_weak_count = --weak_count_;
|
||||
@ -177,7 +166,7 @@ public:
|
||||
|
||||
long use_count() const // nothrow
|
||||
{
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
mutex_type::scoped_lock lock(mtx_);
|
||||
#endif
|
||||
return use_count_;
|
||||
@ -193,29 +182,16 @@ private:
|
||||
long use_count_;
|
||||
long weak_count_;
|
||||
|
||||
#ifdef BOOST_HAS_THREADS
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
mutable mutex_type mtx_;
|
||||
#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:
|
||||
//
|
||||
#ifdef __CODEGUARD__
|
||||
#pragma option push -Vx-
|
||||
# pragma option push -Vx-
|
||||
#endif
|
||||
|
||||
template<class P, class D> class counted_base_impl: public counted_base
|
||||
@ -273,16 +249,11 @@ private:
|
||||
|
||||
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
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P p, D d, void const * = 0): pi_(0)
|
||||
template<class P, class D> shared_count(P p, D d): pi_(0)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
@ -309,11 +280,6 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class P, class D> shared_count(P, D, counted_base * pi): pi_(pi)
|
||||
{
|
||||
pi_->add_ref();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_AUTO_PTR
|
||||
|
||||
// auto_ptr<Y> is special cased to provide the strong guarantee
|
||||
@ -328,21 +294,21 @@ public:
|
||||
|
||||
~shared_count() // nothrow
|
||||
{
|
||||
pi_->release();
|
||||
if(pi_ != 0) pi_->release();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->add_ref();
|
||||
pi_->release();
|
||||
if(tmp != 0) tmp->add_ref();
|
||||
if(pi_ != 0) pi_->release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
@ -357,12 +323,12 @@ public:
|
||||
|
||||
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
|
||||
{
|
||||
return pi_->use_count() == 1;
|
||||
return use_count() == 1;
|
||||
}
|
||||
|
||||
friend inline bool operator==(shared_count const & a, shared_count const & b)
|
||||
@ -377,7 +343,7 @@ public:
|
||||
};
|
||||
|
||||
#ifdef __CODEGUARD__
|
||||
#pragma option pop
|
||||
# pragma option pop
|
||||
#endif
|
||||
|
||||
|
||||
@ -391,30 +357,30 @@ private:
|
||||
|
||||
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
|
||||
{
|
||||
pi_->weak_add_ref();
|
||||
if(pi_ != 0) pi_->weak_add_ref();
|
||||
}
|
||||
|
||||
weak_count(weak_count const & r): pi_(r.pi_) // nothrow
|
||||
{
|
||||
pi_->weak_add_ref();
|
||||
if(pi_ != 0) pi_->weak_add_ref();
|
||||
}
|
||||
|
||||
~weak_count() // nothrow
|
||||
{
|
||||
pi_->weak_release();
|
||||
if(pi_ != 0) pi_->weak_release();
|
||||
}
|
||||
|
||||
weak_count & operator= (shared_count const & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->weak_add_ref();
|
||||
pi_->weak_release();
|
||||
if(tmp != 0) tmp->weak_add_ref();
|
||||
if(pi_ != 0) pi_->weak_release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
@ -423,8 +389,8 @@ public:
|
||||
weak_count & operator= (weak_count const & r) // nothrow
|
||||
{
|
||||
counted_base * tmp = r.pi_;
|
||||
tmp->weak_add_ref();
|
||||
pi_->weak_release();
|
||||
if(tmp != 0) tmp->weak_add_ref();
|
||||
if(pi_ != 0) pi_->weak_release();
|
||||
pi_ = tmp;
|
||||
|
||||
return *this;
|
||||
@ -439,7 +405,7 @@ public:
|
||||
|
||||
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)
|
||||
@ -455,7 +421,7 @@ public:
|
||||
|
||||
inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
|
||||
{
|
||||
pi_->add_ref();
|
||||
if(pi_ != 0) pi_->add_ref();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
51
include/boost/enable_shared_from_this.hpp
Normal file
51
include/boost/enable_shared_from_this.hpp
Normal 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
|
@ -76,8 +76,14 @@ template<> struct shared_ptr_traits<void const>
|
||||
// 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 intrusive_ptr;
|
||||
template<class T> class enable_shared_from_this;
|
||||
|
||||
template<class T> class shared_ptr
|
||||
{
|
||||
@ -87,18 +93,36 @@ private:
|
||||
// typedef checked_deleter<T> deleter;
|
||||
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:
|
||||
|
||||
typedef T element_type;
|
||||
typedef T value_type;
|
||||
typedef T * pointer;
|
||||
typedef typename detail::shared_ptr_traits<T>::reference reference;
|
||||
|
||||
shared_ptr(): px(0), pn()
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
sp_enable_shared_from_this(p);
|
||||
}
|
||||
|
||||
// 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>
|
||||
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
|
||||
|
||||
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
|
||||
@ -199,7 +222,7 @@ public:
|
||||
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);
|
||||
return *px;
|
||||
@ -246,6 +269,11 @@ public:
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
@ -295,6 +323,18 @@ template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & 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)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
@ -76,11 +76,6 @@ public:
|
||||
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
|
||||
{
|
||||
return pn.use_count();
|
||||
@ -119,27 +114,6 @@ private:
|
||||
|
||||
}; // 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)
|
||||
{
|
||||
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
|
||||
{
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
|
||||
// optimization: avoid throw overhead
|
||||
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);
|
||||
}
|
||||
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>();
|
||||
}
|
||||
}
|
||||
|
||||
// Note: there is no get_pointer overload for weak_ptr.
|
||||
// This is intentional. Even get() will disappear in a
|
||||
// future release; these accessors are too error-prone.
|
||||
#else
|
||||
|
||||
// optimization: avoid try/catch overhead when single threaded
|
||||
return r.use_count() == 0? shared_ptr<T>(): shared_ptr<T>(r);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
2374
shared_ptr_test.cpp
2374
shared_ptr_test.cpp
File diff suppressed because it is too large
Load Diff
@ -24,11 +24,6 @@
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
bool boost_error(char const *, char const *, char const *, long)
|
||||
{
|
||||
return true; // fail with assert()
|
||||
}
|
||||
|
||||
class Incomplete;
|
||||
|
||||
Incomplete * get_ptr( boost::shared_ptr<Incomplete>& incomplete )
|
||||
@ -164,7 +159,6 @@ void test()
|
||||
cp.reset();
|
||||
BOOST_TEST( cp2.use_count() == 2 );
|
||||
BOOST_TEST( cp3.use_count() == 2 );
|
||||
BOOST_TEST( cp.use_count() == 1 );
|
||||
cp.reset( new int );
|
||||
*cp = 98765;
|
||||
BOOST_TEST( *cp == 98765 );
|
||||
|
Reference in New Issue
Block a user