| // |
| // esft_constructor_test.cpp |
| // |
| // A test for the new enable_shared_from_this support for calling |
| // shared_from_this from constructors (that is, prior to the |
| // object's ownership being passed to an external shared_ptr). |
| // |
| // Copyright (c) 2008 Frank Mori Hess |
| // Copyright (c) 2008 Peter Dimov |
| // |
| // Distributed under the Boost Software License, Version 1.0. |
| // |
| // See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| |
| #include <boost/smart_ptr/enable_shared_from_this2.hpp> |
| #include <boost/shared_ptr.hpp> |
| #include <boost/weak_ptr.hpp> |
| #include <boost/detail/lightweight_test.hpp> |
| #include <memory> |
| |
| class X: public boost::enable_shared_from_this2< X > |
| { |
| private: |
| |
| int destroyed_; |
| int deleted_; |
| int expected_; |
| |
| private: |
| |
| X( X const& ); |
| X& operator=( X const& ); |
| |
| public: |
| |
| static int instances; |
| |
| public: |
| |
| explicit X( int expected, boost::shared_ptr<X> *early_px = 0 ): destroyed_( 0 ), deleted_( 0 ), expected_( expected ) |
| { |
| ++instances; |
| if( early_px ) *early_px = shared_from_this(); |
| } |
| |
| ~X() |
| { |
| BOOST_TEST( deleted_ == expected_ ); |
| BOOST_TEST( destroyed_ == 0 ); |
| ++destroyed_; |
| --instances; |
| } |
| |
| typedef void (*deleter_type)( X* ); |
| |
| static void deleter( X * px ) |
| { |
| ++px->deleted_; |
| } |
| |
| static void deleter2( X * px ) |
| { |
| ++px->deleted_; |
| delete px; |
| } |
| }; |
| |
| int X::instances = 0; |
| |
| template<typename T, typename U> |
| bool are_shared_owners(const boost::shared_ptr<T> &a, const boost::shared_ptr<U> &b) |
| { |
| return !(a < b) && !(b < a); |
| } |
| |
| struct Y: public boost::enable_shared_from_this2<Y> |
| {}; |
| |
| int main() |
| { |
| BOOST_TEST( X::instances == 0 ); |
| |
| { |
| boost::shared_ptr<X> early_px; |
| X* x = new X( 1, &early_px ); |
| BOOST_TEST( early_px.use_count() > 0 ); |
| BOOST_TEST( boost::get_deleter<X::deleter_type>(early_px) == 0 ); |
| boost::shared_ptr<X> px( x, &X::deleter2 ); |
| BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 ); |
| BOOST_TEST(are_shared_owners(early_px, px)); |
| px.reset(); |
| BOOST_TEST( early_px.use_count() == 1 ); |
| BOOST_TEST( X::instances == 1 ); |
| // X::deleter_type *pd = boost::get_deleter<X::deleter_type>(early_px); |
| // BOOST_TEST(pd && *pd == &X::deleter2 ); |
| } |
| |
| BOOST_TEST( X::instances == 0 ); |
| |
| { |
| boost::shared_ptr<X> early_px; |
| X* x = new X( 1, &early_px ); |
| boost::weak_ptr<X> early_weak_px = early_px; |
| early_px.reset(); |
| BOOST_TEST( !early_weak_px.expired() ); |
| boost::shared_ptr<X> px( x, &X::deleter2 ); |
| BOOST_TEST( px.use_count() == 1 ); |
| BOOST_TEST( X::instances == 1 ); |
| BOOST_TEST(are_shared_owners(early_weak_px.lock(), px)); |
| px.reset(); |
| BOOST_TEST( early_weak_px.expired() ); |
| } |
| |
| BOOST_TEST( X::instances == 0 ); |
| |
| { |
| boost::shared_ptr<X> early_px; |
| X x( 1, &early_px ); |
| BOOST_TEST( early_px.use_count() > 0 ); |
| boost::shared_ptr<X> px( &x, &X::deleter ); |
| BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 ); |
| early_px.reset(); |
| BOOST_TEST( px.use_count() == 1 ); |
| BOOST_TEST( X::instances == 1 ); |
| px.reset(); |
| try |
| { |
| x.shared_from_this(); |
| BOOST_ERROR("x did not throw bad_weak_ptr"); |
| } |
| catch( const boost::bad_weak_ptr & ) |
| {} |
| } |
| |
| BOOST_TEST( X::instances == 0 ); |
| |
| { |
| boost::weak_ptr<X> early_weak_px; |
| { |
| boost::shared_ptr<X> early_px; |
| X x( 0, &early_px ); |
| early_weak_px = early_px; |
| early_px.reset(); |
| BOOST_TEST( !early_weak_px.expired() ); |
| BOOST_TEST( X::instances == 1 ); |
| } |
| BOOST_TEST( early_weak_px.expired() ); |
| } |
| |
| BOOST_TEST( X::instances == 0 ); |
| |
| { |
| boost::shared_ptr<Y> px(new Y()); |
| Y y(*px); |
| px.reset(); |
| try |
| { |
| y.shared_from_this(); |
| } |
| catch( const boost::bad_weak_ptr & ) |
| { |
| BOOST_ERROR("y threw bad_weak_ptr"); |
| } |
| } |
| |
| return boost::report_errors(); |
| } |