Boost logo

Boost :

Subject: [boost] enable_shared_from_this2
From: Berserker (berserker_r_at_[hidden])
Date: 2009-10-26 07:07:38


After experiencing some troubles with boost::python and
enable_shared_from_this (as already reported in the past by someone to
Peter Dimov), I started looking at the new (not documented) class
enable_shared_from_this2.
I made two changes in init_weak_once and now it seems to support
shared_from_this in constructors and shared pointers "reinitialization".
The original code (from boost 1.40):

void init_weak_once() const
{
    if( weak_this_._empty() )
    {
       shared_this_.reset(static_cast< T* >( 0 ),
detail::esft2_deleter_wrapper());
       weak_this_ = shared_this_;
    }
}

The "patched" code:

void init_weak_once() const
{
    // Reinitialization support
    if( weak_this_.expired() )
    {
       // shared_from_this in costructors support
shared_this_.reset(static_cast
<T*>(const_cast<enable_shared_from_this2>(this)),
detail::esft2_deleter_wrapper());
       weak_this_ = shared_this_;
    }
}

I know that the static_cast/const_cast is "problematic" on VC6 (and
maybe other compilers) but it could be solved using an offset from
enable_shared_from_this2 * to T *.
I've attached a testcase that shows the problems with the current
enable_shared_from_this2 implementation (with the proposed patch it works).
Any feedback about this?

struct null_deleter
{
        template <typename T>
        inline void operator()(T *p) const { }
};

class EnableThisPtrTester : public boost::enable_shared_from_this2<EnableThisPtrTester>
{
public:
        EnableThisPtrTester()
        {

        }

        EnableThisPtrTester(shared_ptr<EnableThisPtrTester> &ptr)
        {
                ptr = shared_from_this();
                BOOST_CHECK(ptr);
        }
};

BOOST_AUTO_TEST_CASE(test_enable_this_ptr)
{
        {
                shared_ptr<EnableThisPtrTester> ptr1;
                shared_ptr<EnableThisPtrTester> ptr2(new EnableThisPtrTester(ptr1));
                BOOST_CHECK(ptr1 == ptr2);
                BOOST_CHECK(ptr1.use_count() == ptr2.use_count());
                BOOST_CHECK(ptr1->shared_from_this() == ptr1);
                BOOST_CHECK(ptr1->shared_from_this().use_count() == ptr1.use_count());
                shared_ptr<EnableThisPtrTester> ptr3 = ptr2->shared_from_this();
                BOOST_CHECK(ptr2 == ptr3);
                BOOST_CHECK(ptr2.use_count() == ptr3.use_count());
                BOOST_CHECK(ptr1->shared_from_this().use_count() == ptr1.use_count());
        }

        {
                shared_ptr<EnableThisPtrTester> ptr1;
                EnableThisPtrTester tester(ptr1);
                shared_ptr<EnableThisPtrTester> ptr2 = tester.shared_from_this();
                BOOST_CHECK(ptr1 == ptr2);
                BOOST_CHECK(ptr1.use_count() == ptr2.use_count());

                ptr1.reset();
                ptr2.reset();
        }

        {
                EnableThisPtrTester tester;

                {
                        shared_ptr<EnableThisPtrTester> ptr1 = tester.shared_from_this();
                        shared_ptr<EnableThisPtrTester> ptr2 = tester.shared_from_this();
                        BOOST_CHECK(ptr1 == ptr2);
                        BOOST_CHECK(ptr1.use_count() == ptr2.use_count());

                        shared_ptr<EnableThisPtrTester> ptr3(&tester, null_deleter());

                        BOOST_CHECK(ptr1 == ptr3);
                        BOOST_CHECK(ptr1.use_count() == ptr3.use_count());

                        shared_ptr<EnableThisPtrTester> ptr4 = tester.shared_from_this();
                        BOOST_CHECK(ptr4 == ptr1);
                        BOOST_CHECK(ptr4 == ptr3);

                        BOOST_CHECK(ptr1.use_count() == ptr4.use_count());
                        BOOST_CHECK(ptr3.use_count() == ptr4.use_count());
                }

                BOOST_CHECK(tester.shared_from_this());
        }
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk