enable_shared_from_this()

Can someone please explain why this code: struct Foo : boost::enable_shared_from_this<Foo> {}; Foo* p_foo = new Foo; boost::shared_ptr<Foo> ptr_foo(p_foo->shared_from_this()); is throwing? msvcr100d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 157 C++ boost::throw_exceptionboost::bad_weak_ptr(const boost::bad_weak_ptr & e) Line 61 + 0x4d bytes C++ boost::detail::shared_count::shared_count(const boost::detail::weak_count & r) Line 421 + 0x23 bytes C++ boost::shared_ptr<`anonymous namespace'::Foo>::shared_ptr<`anonymous namespace'::Foo><`anonymous namespace'::Foo>(const boost::weak_ptr<`anonymous namespace'::Foo> & r) Line 216 C++ boost::enable_shared_from_this<`anonymous namespace'::Foo>::shared_from_this() Line 49 + 0xf bytes C++
`anonymous namespace'::test_method() Line 41 + 0xf bytes C++
Since Foo embeds a weak_ptr, why can't it new the pi_ on the spot? (I'm using Boost 1.44). Thanks, --DD PS: On a related note, why doesn't boost::shared_ptr<Foo>(p_foo) (where p_foo is a raw Foo*) implicitly apply the aliasing Ctor, to share the same px, to avoid the classic bug of having several different pn on the same px, since p_foo derives from enable_shared_from_this()? Initially i thought that's what sp_enable_shared_from_this() and pe->_internal_accept_owner() were meant to do, but obviously that's not the case.

Can someone please explain why this code:
struct Foo : boost::enable_shared_from_this<Foo> {}; Foo* p_foo = new Foo; boost::shared_ptr<Foo> ptr_foo(p_foo->shared_from_this());
is throwing?
At the time you call shared_from_this, no shared_ptr has been created to hold p_foo. The weak_ptr assumes the memory has been deallocated, since
Hi Dominique, Dominique Devienne wrote: there are no shared_ptrs pointing to it. Inheriting from enable_shared_from_this is a guarantee that you will store the pointer in a shared_ptr -- it's a precondition of calling shared_from_this. Since Foo embeds a weak_ptr, why can't it new the pi_ on the spot?
(I'm using Boost 1.44).
Hmm, it might be interesting to have shared_from_this create a shared_ptr if none exists, but I don't know what that might complicate -- perhaps it would cause issues at destruction?
PS: On a related note, why doesn't boost::shared_ptr<Foo>(p_foo) (where p_foo is a raw Foo*) implicitly apply the aliasing Ctor, to share the same px, to avoid the classic bug of having several different pn on the same px, since p_foo derives from enable_shared_from_this()? Initially i thought that's what sp_enable_shared_from_this() and pe->_internal_accept_owner() were meant to do, but obviously that's not the case.
I suspect something like this could be made to work if the previous also worked -- but the class is documented to *not* allow the previous to work. I'd have to think about why (or maybe Peter will enlighten us). HTH, Nate

On Mon, Feb 4, 2013 at 6:23 PM, Nathan Crookston
Since Foo embeds a weak_ptr, why can't it new the pi_ on the spot? (I'm using Boost 1.44).
Hmm, it might be interesting to have shared_from_this create a shared_ptr if none exists, but I don't know what that might complicate -- perhaps it would cause issues at destruction?
I don't see the difference between the shared_ptr being created from the "inside" or the "outside", as far as that pi_ is concerned.
PS: On a related note, why doesn't boost::shared_ptr<Foo>(p_foo) (where p_foo is a raw Foo*) implicitly apply the aliasing Ctor, to share the same px, to avoid the classic bug of having several different pn on the same px, since p_foo derives from enable_shared_from_this()? Initially i thought that's what sp_enable_shared_from_this() and pe->_internal_accept_owner() were meant to do, but obviously that's not the case.
I suspect something like this could be made to work if the previous also worked -- but the class is documented to *not* allow the previous to work. I'd have to think about why (or maybe Peter will enlighten us).
Indeed, I (naively) think it can work, and I'm interested in finding out why this was not implemented, especially whether it was conscious decision (rational?) or simply overlooked. There's already code that tightly couples shared_ptr/weak_ptr/enable_shared_from_this, so it seems that making shared_ptr even safer in the special case that T is-a enable_shared_from_this<T>, to enforce using a single pn (the one embedded in the base enable_shared_from_this<T>) given a T*, is a "good thing", no? I've emulated that behavior using shared_from_ptr() below, to avoid a crash from the "normally big NO-NO!" line in the test (also below), just as a proof-of-concept, although of course catching the exception like this is hardly pretty. Could easily be made to work whether T is-a boost::enable_shared_from_this<T> or not too, but really we'd want this little machinery to be built-in to shared_ptr, don't you think? Thanks for any insight on this. Could very well be I'm missing something obvious (my C++ expertise doesn't rise to Boost levels), but so far I fail to see the drawbacks. Thanks, --DD struct Foo : boost::enable_shared_from_this<Foo> { static int count__; Foo() { ++count__; } ~Foo() { --count__; BOOST_ASSERT(count__ >= 0); } }; int Foo::count__ = 0; template <typename T> boost::shared_ptr<T> shared_from_ptr(T* p_t) { try { boost::enable_shared_from_this<T>* p_this = p_t; // for more obvious error messages return p_this->shared_from_this(); } catch (const boost::bad_weak_ptr&) { return boost::shared_ptr<T>(p_t); } } BOOST_AUTO_TEST_SUITE(MY_TEST) BOOST_AUTO_TEST_CASE(test_shared_from_ptr) { BOOST_CHECK(Foo::count__ == 0); { boost::shared_ptr<Foo> foo_ptr1 = shared_from_ptr(new Foo); BOOST_CHECK(Foo::count__ == 1); BOOST_CHECK(foo_ptr1.unique()); BOOST_CHECK(foo_ptr1.unique()); boost::shared_ptr<Foo> foo_ptr2 = shared_from_ptr(foo_ptr1.get()); // normally big NO-NO! BOOST_CHECK(Foo::count__ == 1); BOOST_CHECK(!foo_ptr1.unique()); BOOST_CHECK(!foo_ptr2.unique()); } BOOST_CHECK(Foo::count__ == 0); } ...

On Tue, Feb 5, 2013 at 2:10 AM, Dominique Devienne
On Mon, Feb 4, 2013 at 6:23 PM, Nathan Crookston
wrote: Since Foo embeds a weak_ptr, why can't it new the pi_ on the spot? (I'm using Boost 1.44).
Hmm, it might be interesting to have shared_from_this create a shared_ptr if none exists, but I don't know what that might complicate -- perhaps it would cause issues at destruction?
I don't see the difference between the shared_ptr being created from the "inside" or the "outside", as far as that pi_ is concerned.
PS: On a related note, why doesn't boost::shared_ptr<Foo>(p_foo) (where p_foo is a raw Foo*) implicitly apply the aliasing Ctor, to share the same px, to avoid the classic bug of having several different pn on the same px, since p_foo derives from enable_shared_from_this()? Initially i thought that's what sp_enable_shared_from_this() and pe->_internal_accept_owner() were meant to do, but obviously that's not the case.
I suspect something like this could be made to work if the previous also worked -- but the class is documented to *not* allow the previous to work. I'd have to think about why (or maybe Peter will enlighten us).
Indeed, I (naively) think it can work, and I'm interested in finding out why this was not implemented, especially whether it was conscious decision (rational?) or simply overlooked.
Consider this simple example: int MyThing::Foo() { shared_from_this(); return this->x; } If enable_shared_from_this created a shared_ptr for you, then the last reference would have been destroyed and this would be deleted, leading to undefined behavior. A real-world example might be passing shared_from_this() as part of a callback to some function (or any other of the uses of enable_shared_from_this). Your proposal would make legitimate-looking code lead to undefined behavior depending on how the instance was constructed (if it was stored in a shared_ptr). This would be doubly-confusing if you used shared_from_this() in the constructor. And then you'd have to figure out a way to let a unique_ptr<MyThing> know that it no longer uniquely owns the instance. Or somehow deal with a stack-allocated MyThing. In the current implementation, the call to shared_from_this() will *always* throw a boost::bad_weak_ptr. Sure, it is inconvenient, but it doesn't lead to undefined behavior. I see that as a major advantage.
Thanks for any insight on this. Could very well be I'm missing something obvious (my C++ expertise doesn't rise to Boost levels), but so far I fail to see the drawbacks.
I would suggest looking at intrusive_ptr ( http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/intrusive_ptr.html) or the not-really-documented enable_shared_from_this2 ( http://www.boost.org/doc/libs/1_52_0/boost/smart_ptr/enable_shared_from_this...). Neither solves every problem under the sun, but they might have helpful properties you're looking for. There's already code that tightly couples
shared_ptr/weak_ptr/enable_shared_from_this,
I would disagree with the statement that shared_ptr and weak_ptr are coupled with enable_shared_from_this -- they can exist perfectly fine without them (but enable_shared_from_this can't exist without both). The only coupling shared_ptr has with weak_ptr is inside the implementation (arguably bad, but whatever). -- Travis Gockel λ Combinator

Can someone please explain why this code:
struct Foo : boost::enable_shared_from_this<Foo> {}; Foo* p_foo = new Foo; boost::shared_ptr<Foo> ptr_foo(p_foo->shared_from_this());
is throwing?
The documentation explains:
http://www.boost.org/doc/libs/1_52_0/libs/smart_ptr/enable_shared_from_this....
<
participants (4)
-
Dominique Devienne
-
Igor R
-
Nathan Crookston
-
Travis Gockel