
Hi Colin, I had soimilar problem using boost 1.25.8. Here is my own modified implementation of smart pointers based on the non thread safe boost one. Hope this will help you, Seb. #ifndef BOOST_SMART_PTR_HPP #define BOOST_SMART_PTR_HPP #include <boost/config.hpp> // for broken compiler workarounds #include <cstddef> // for std::size_t #include <memory> // for std::auto_ptr #include <algorithm> // for std::swap #include <boost/utility.hpp> // for boost::noncopyable, checked_delete, checked_array_delete #include <functional> // for std::less #include <boost/static_assert.hpp> // for BOOST_STATIC_ASSERT // Added by seb #include <boost/thread/mutex.hpp> #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) # pragma warning(disable:4284) // return type for 'identifier::operator->' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation #endif namespace boost { // scoped_ptr --------------------------------------------------------------// // scoped_ptr mimics a built-in pointer except that it guarantees deletion // of the object pointed to, either on destruction of the scoped_ptr or via // an explicit reset(). scoped_ptr is a simple solution for simple needs; // see shared_ptr (below) or std::auto_ptr if your needs are more complex. template<typename T> class scoped_ptr : noncopyable { T* ptr; public: typedef T element_type; explicit scoped_ptr( T* p=0 ) : ptr(p) {} // never throws ~scoped_ptr() { checked_delete(ptr); } void reset( T* p=0 ) { if ( ptr != p ) { checked_delete(ptr); ptr = p; } } T& operator*() const { return *ptr; } // never throws T* operator->() const { return ptr; } // never throws T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return ptr; } // never throws #endif }; // scoped_ptr // scoped_array ------------------------------------------------------------// // scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to // is guaranteed, either on destruction of the scoped_array or via an explicit // reset(). See shared_array or std::vector if your needs are more complex. template<typename T> class scoped_array : noncopyable { T* ptr; public: typedef T element_type; explicit scoped_array( T* p=0 ) : ptr(p) {} // never throws ~scoped_array() { checked_array_delete(ptr); } void reset( T* p=0 ) { if ( ptr != p ) {checked_array_delete(ptr); ptr=p;} } T* get() const { return ptr; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return ptr; } // never throws #else T& operator[](std::size_t i) const { return ptr[i]; } // never throws #endif }; // scoped_array // shared_ptr --------------------------------------------------------------// // An enhanced relative of scoped_ptr with reference counted copy semantics. // The object pointed to is deleted when the last shared_ptr pointing to it // is destroyed or reset. template<typename T> class shared_ptr { public: typedef T element_type; explicit shared_ptr(T* p =0) : px(p) { try { // Added by seb to be able to delete pn is new throws pn = NULL; pn = new long(1); // Added by seb. pm = new mutex(); } // fix: prevent leak if new throws catch (...) { checked_delete(p); // Added by seb: delete mutex tom prevent memory leaks checked_delete(pm); throw; } } ~shared_ptr() { dispose(); } #if !defined( BOOST_NO_MEMBER_TEMPLATES ) || defined (BOOST_MSVC6_MEMBER_TEMPLATES) template<typename Y> shared_ptr(const shared_ptr<Y>& r) : px(r.px) { // never throws // Added by seb: Take the shared mutex here to be safe when // we are incrementing the reference count. // First share the same mutex. pm = r.pm; mutex::scoped_lock l(*pm); // End of seb's modif ++*(pn = r.pn); } #ifndef BOOST_NO_AUTO_PTR template<typename Y> explicit shared_ptr(std::auto_ptr<Y>& r) { pn = new long(1); // may throw // Added by seb. pm = new mutex(); // may throw px = r.release(); // fix: moved here to stop leak if new throws } #endif template<typename Y> shared_ptr& operator=(const shared_ptr<Y>& r) { share(r.px,r.pn, r.pm); return *this; } #ifndef BOOST_NO_AUTO_PTR template<typename Y> shared_ptr& operator=(std::auto_ptr<Y>& r) { // code choice driven by guarantee of "no effect if new throws" // Added by seb - synchronize all this thing mutex::scoped_lock l(*pm); if (*pn == 1) { checked_delete(px); } else { // allocate new reference counter long * tmp = new long(1); // may throw --*pn; // only decrement once danger of new throwing is past pn = tmp; } // allocate new reference counter px = r.release(); // fix: moved here so doesn't leak if new throws return *this; } #endif #else #ifndef BOOST_NO_AUTO_PTR explicit shared_ptr(std::auto_ptr<T>& r) { pn = new long(1); // may throw // Added by seb - Instanciate the mutex pm = new mutex(); px = r.release(); // fix: moved here to stop leak if new throws } shared_ptr& operator=(std::auto_ptr<T>& r) { // code choice driven by guarantee of "no effect if new throws" mutex::scoped_lock l(*pm); if (*pn == 1) { checked_delete(px); } else { // allocate new reference counter long * tmp = new long(1); // may throw --*pn; // only decrement once danger of new throwing is past pn = tmp; } // allocate new reference counter px = r.release(); // fix: moved here so doesn't leak if new throws return *this; } #endif #endif // Added by seb to be able to downcast a shared_ptr template<class Derived> void downcasted_copy_to(shared_ptr<Derived>& q) const { Derived* rawq = dynamic_cast<Derived*>(px); if(!rawq || !px) { q = shared_ptr<Derived>(); } else { shared_ptr<Derived> ptmp; ptmp.px = rawq; { mutex::scoped_lock l(*pm); ++*pn; } ptmp.pn = pn; ptmp.pm = pm; q.swap(ptmp); } } // End seb's addition // The assignment operator and the copy constructor must come after // the templated versions for MSVC6 to work. (Gary Powell) shared_ptr(const shared_ptr& r) : px(r.px), // Added by seb pm(r.pm) { // Added by seb mutex::scoped_lock l(*pm); ++*(pn = r.pn); } // never throws shared_ptr& operator=(const shared_ptr& r) { share(r.px,r.pn, r.pm); return *this; } void reset(T* p=0) { if ( px == p ) return; // fix: self-assignment safe // Added by seb mutex::scoped_lock l(*pm); if (--*pn == 0) { checked_delete(px); } else { // allocate new reference counter try { // Added by seb pm = NULL; pn = new long; // Added by seb pm = new mutex(); } // fix: prevent leak if new throws catch (...) { ++*pn; // undo effect of --*pn above to meet effects guarantee checked_delete(p); // Added by seb checked_delete(pm); throw; } // catch } // allocate new reference counter // If an other smart pointer had a reference of the pointer, // then we have taken the common mutex. // In the other case, our pointer is not yet shared, therefore // we don't need to take a lock here. *pn = 1; px = p; } // reset T& operator*() const { return *px; } // never throws T* operator->() const { return px; } // never throws T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return px; } // never throws #endif long use_count() const { // Added by Seb mutex::scoped_lock l(*pm); return *pn; } // never throws bool unique() const { mutex::scoped_lock l(*pm); return *pn == 1; } // never throws void swap(shared_ptr<T>& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); // Added by seb std::swap(pm, other.pm); } // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) // Don't split this line into two; that causes problems for some GCC 2.95.2 builds #if ( defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) ) || !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) private: #endif T* px; // contained pointer long* pn; // ptr to reference counter // Added by seb mutex* pm; // Don't split this line into two; that causes problems for some GCC 2.95.2 builds #if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) template<typename Y> friend class shared_ptr; #endif void dispose() { long ref; { mutex::scoped_lock l(*pm); ref = --*pn; } if (ref == 0) { checked_delete(px); delete pn; // Added by seb delete pm; } } // rpm added by seb void share(T* rpx, long* rpn, mutex* rpm) { mutex::scoped_lock l(*rpm); if (pn != rpn) { // Q: why not px != rpx? A: fails when both == 0 ++*rpn; // done before dispose() in case rpn transitively // dependent on *this (bug reported by Ken Johnson) dispose(); px = rpx; pn = rpn; pm = rpm; } } // share }; // shared_ptr template<typename T, typename U> inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) { return a.get() == b.get(); } template<typename T, typename U> inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) { return a.get() != b.get(); } // shared_array ------------------------------------------------------------// // shared_array extends shared_ptr to arrays. // The array pointed to is deleted when the last shared_array pointing to it // is destroyed or reset. template<typename T> class shared_array { public: typedef T element_type; explicit shared_array(T* p =0) : px(p) { try { pn = new long(1); } // fix: prevent leak if new throws catch (...) { checked_array_delete(p); throw; } } shared_array(const shared_array& r) : px(r.px) // never throws { ++*(pn = r.pn); } ~shared_array() { dispose(); } shared_array& operator=(const shared_array& r) { if (pn != r.pn) { // Q: why not px != r.px? A: fails when both px == 0 ++*r.pn; // done before dispose() in case r.pn transitively // dependent on *this (bug reported by Ken Johnson) dispose(); px = r.px; pn = r.pn; } return *this; } // operator= void reset(T* p=0) { if ( px == p ) return; // fix: self-assignment safe if (--*pn == 0) { checked_array_delete(px); } else { // allocate new reference counter try { pn = new long; } // fix: prevent leak if new throws catch (...) { ++*pn; // undo effect of --*pn above to meet effects guarantee checked_array_delete(p); throw; } // catch } // allocate new reference counter *pn = 1; px = p; } // reset T* get() const { return px; } // never throws #ifdef BOOST_SMART_PTR_CONVERSION // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk! operator T*() const { return px; } // never throws #else T& operator[](std::size_t i) const { return px[i]; } // never throws #endif long use_count() const { return *pn; } // never throws bool unique() const { return *pn == 1; } // never throws void swap(shared_array<T>& other) // never throws { std::swap(px,other.px); std::swap(pn,other.pn); } private: T* px; // contained pointer long* pn; // ptr to reference counter void dispose() { if (--*pn == 0) { checked_array_delete(px); delete pn; } } }; // shared_array template<typename T> inline bool operator==(const shared_array<T>& a, const shared_array<T>& b) { return a.get() == b.get(); } template<typename T> inline bool operator!=(const shared_array<T>& a, const shared_array<T>& b) { return a.get() != b.get(); } // Added by seb for downcasting capability template<class Tout, class Tin> shared_ptr<Tout> do_dynamic_cast(const shared_ptr<Tin>& p) { shared_ptr<Tout> pout; p.downcasted_copy_to(pout); return pout; } } // namespace boost // specializations for things in namespace std -----------------------------// #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION namespace std { // Specialize std::swap to use the fast, non-throwing swap that's provided // as a member function instead of using the default algorithm which creates // a temporary and uses assignment. template<typename T> inline void swap(boost::shared_ptr<T>& a, boost::shared_ptr<T>& b) { a.swap(b); } template<typename T> inline void swap(boost::shared_array<T>& a, boost::shared_array<T>& b) { a.swap(b); } // Specialize std::less so we can use shared pointers and arrays as keys in // associative collections. // It's still a controversial question whether this is better than supplying // a full range of comparison operators (<, >, <=,
=).
template<typename T> struct less< boost::shared_ptr<T> > : binary_function<boost::shared_ptr<T>, boost::shared_ptr<T>, bool> { bool operator()(const boost::shared_ptr<T>& a, const boost::shared_ptr<T>& b) const { return less<T*>()(a.get(),b.get()); } }; template<typename T> struct less< boost::shared_array<T> > : binary_function<boost::shared_array<T>, boost::shared_array<T>, bool> { bool operator()(const boost::shared_array<T>& a, const boost::shared_array<T>& b) const { return less<T*>()(a.get(),b.get()); } }; } // namespace std #endif // ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION #ifdef BOOST_MSVC # pragma warning(pop) #endif #endif // BOOST_SMART_PTR_HPP __________________________________________________ Do You Yahoo!? Got something to say? Say it better with Yahoo! Video Mail http://mail.yahoo.com