Boost logo

Boost Users :

Subject: Re: [Boost-users] enable_shared_from_this()
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2013-02-05 04:10:48


On Mon, Feb 4, 2013 at 6:23 PM, Nathan Crookston
<nathan.crookston_at_[hidden]> 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.

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);
}
...


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net