shared_from_this from a destructor

(This message is also posted on sourceforge. Please forgive the double posting, but I am still unfamiliar with the community...) version: boost 1.30.0 library: smart pointers I am using the boost::enable_shared_from_this base class from the smart pointer library to implement shared_from_this in my classes. I was amazed to find this class, after hours of thashing trying even to figure out the very problem it solves. So, first off, thanks to the boosters. My problem is that shared_from_this() throws boost::bad_weak_ptr if called from my class's destructor. Is this a design decision? a bug? am I misreading a class requirement? The problem (if it is one...) is that sp_counted_base::release() decrements use_count_ before calling dispose(). Then when my class calls shared_from_this from its destructor (via dispose()), sp_counted_base::add_ref fails (use_count == 0) and throws boost::bad_weak_ptr. I would suggest either setting use_count_ after dispose(), or clarifying in the docs that shared_from_this can't be called from a destructor. (... which would send me back to the drawing board to solve my problem) It would also be handy to have an exception less version of share_from_this which justs returns a null shared_ptr. Thanks for any help. ... Michael Ost Something like this (warning: uncompiled, untested!) ... class T : public enable_shared_from_this { public: T() {} ~T() { shared_ptr<T> ptr = shared_from_this(); // trouble: exception, can't get a shared_ptr } }; main() { shared_ptr<T> ptr = shared_ptr(new T()); ptr.reset(); }

ostware wrote:
class T : public enable_shared_from_this { public: T() {} ~T() { shared_ptr<T> ptr = shared_from_this(); // trouble: exception, can't get a shared_ptr
What are you trying to achieve with this? ~T has already started; the object is on its way to A Better Place. Even if you could get a shared_ptr to it, you can't stop the object's destruction. The shared_ptr would point to a destroyed T once ~T finishes. If you want to have a shared_ptr instance to 'this' that is valid only for the duration of ~T, you can use a null deleter, as described in http://www.boost.org/libs/smart_ptr/sp_techniques.html#static HTH
} };

ostware wrote:
class T : public enable_shared_from_this { public: T() {} ~T() { shared_ptr<T> ptr = shared_from_this(); // trouble: exception, can't get a shared_ptr
What are you trying to achieve with this? ~T has already started;
--- In Boost-Users@yahoogroups.com, "Peter Dimov"
is on its way to A Better Place. Even if you could get a shared_ptr to it, you can't stop the object's destruction. The shared_ptr would point to a destroyed T once ~T finishes.
(First off, thanks for the reply. I am feeling my way in the dark here and I could easily be missing something obvious. But perhaps it would help 'boost' to clarify or fix this, as needed. I keep having that 'what is going on!' feeling from boost that I got from STL, when I first started digging into it. But I am also excited by the possiblities of boost. Onward! So...) ~T needs to tell another object it holds a pointer to (say class U) that it is 'going away' during its destructor. T and U are loosely connected, from two different libraries, and each holds a weak_ptr to the other. When U finds out that T is 'going away' it needs to void out its weak_ptr<T>. I am converting code where the weak_ptrs were simple U* or T*. I think this code distills it down as much as possible. Obviously there is more going on, but I think this sums it up... class T : enable_shared_from_this<T> { ~T() { shared_ptr<U> u = m_u.lock(); if (u) { shared_ptr<T> ptr(shared_from_this()); // exception! u->UnsetT(ptr); } } void SetU(shared_ptr<U> u) { shared_ptr<T> ptr(shared_from_this()); t->SetT(ptr); m_u = u; } private: weak_ptr<U> m_u; }; class U { public: void SetT(shared_ptr<T> t) { m_t = t; } void UnsetT(shared_ptr<T> t) { if (t == m_t.lock()) m_t.reset(); } private: weak_ptr<T> m_t; }; main() { shared_ptr<T> t(new T); shared_ptr<U> u(new U); t->SetU(u); t.reset(); // u->m_t should have been voided out } Your null_deleter suggestion was good. I tried it and it worked. So using the below works... ~T() { shared_ptr<T> ptr(this, null_deleter()); m_u->UnsetT(ptr); } It also worked to move the use_count_-- down past dispose() in boost/detail/shared_count.hpp::release()... shared_count::release() { { mutex_type::scoped_lock lock(mtx_); long new_use_count = use_count_ - 1; if (new_use_count != 0) { --use_count_; --weak_count_; return; } } dispose(); use_count_ = new_use_count; weak_release(); } The use of the mutex doesn't look kosher, but you get the idea (and I am handling thread safety elsewhere anyway). So it seems that either (1) this is a bug to fix, or (2) it should be documented that shared_from_this doesn't work in destructors (or constructors for that matter). Cheers... mo

ostware wrote:
~T needs to tell another object it holds a pointer to (say class U) that it is 'going away' during its destructor. T and U are loosely connected, from two different libraries, and each holds a weak_ptr to the other. When U finds out that T is 'going away' it needs to void out its weak_ptr<T>. I am converting code where the weak_ptrs were simple U* or T*.
You don't need to do anything. A weak_ptr is "voided" automagically when its object (managed by a shared_ptr) goes away. ;-)
participants (2)
-
ostware
-
Peter Dimov