diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 8756294..cf97746 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -25,6 +25,8 @@ #include #include +#include // for std::less + namespace boost { @@ -215,6 +217,16 @@ public: { return pi_->use_count() == 1; } + + friend inline bool operator==(shared_count const & a, shared_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(shared_count const & a, shared_count const & b) + { + return std::less()(a.pi_, b.pi_); + } }; class weak_count @@ -275,6 +287,16 @@ public: { return pi_->use_count(); } + + friend inline bool operator==(weak_count const & a, weak_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(weak_count const & a, weak_count const & b) + { + return std::less()(a.pi_, b.pi_); + } }; } // namespace detail diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index c13c3a8..76ecdbb 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -29,6 +29,7 @@ #include // for std::auto_ptr #include // for std::swap #include // for std::less +#include // for std::bad_cast #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index 170359d..2b7120e 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -22,7 +22,7 @@ #include #include // for std::swap -#include // for std::less +#include // for std::bad_cast #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) @@ -133,6 +133,11 @@ public: pn.swap(other.pn); } + bool less(this_type const & rhs) const // implementation detail, never throws + { + return pn < rhs.pn; + } + // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) @@ -161,7 +166,7 @@ template inline bool operator!=(weak_ptr const & a, weak_pt template inline bool operator<(weak_ptr const & a, weak_ptr const & b) { - return std::less()(a.get(), b.get()); + return a.less(b); } template void swap(weak_ptr & a, weak_ptr & b) diff --git a/shared_ptr_test.cpp b/shared_ptr_test.cpp index 7387cc8..dc1282a 100644 --- a/shared_ptr_test.cpp +++ b/shared_ptr_test.cpp @@ -46,6 +46,11 @@ struct X std::cout << "X(" << this << ")::~X()\n"; } + virtual int id() const + { + return 1; + } + private: X(X const &); @@ -66,6 +71,11 @@ struct Y: public X std::cout << "Y(" << this << ")::~Y()\n"; } + virtual int id() const + { + return 2; + } + private: Y(Y const &); @@ -86,6 +96,76 @@ void release_object(int * p) std::cout << "release_object()\n"; } +template void test_is_X(T const & p) +{ + BOOST_TEST(p->id() == 1); + BOOST_TEST((*p).id() == 1); +} + +template void test_is_Y(T const & p) +{ + BOOST_TEST(p->id() == 2); + BOOST_TEST((*p).id() == 2); +} + +// std::rel_ops::operator!= breaks x != y when defined in the global namespace + +#if defined(__STL_BEGIN_RELOPS_NAMESPACE) && !defined(__STL_USE_NAMESPACE_FOR_RELOPS) +# define BOOST_BROKEN_INEQUALITY +#endif + +template void test_eq(T const & a, T const & b) +{ + BOOST_TEST(a == b); + +#ifndef BOOST_BROKEN_INEQUALITY + + BOOST_TEST(!(a != b)); + +#endif + + BOOST_TEST(!(a < b)); + BOOST_TEST(!(b < a)); +} + +template void test_ne(T const & a, T const & b) +{ + BOOST_TEST(!(a == b)); + +#ifndef BOOST_BROKEN_INEQUALITY + + BOOST_TEST(a != b); + +#endif + + BOOST_TEST(a < b || b < a); + BOOST_TEST(!(a < b && b < a)); +} + +template void test_eq2(T const & a, U const & b) +{ + BOOST_TEST(a == b); + +#ifndef BOOST_BROKEN_INEQUALITY + + BOOST_TEST(!(a != b)); + +#endif + +} + +template void test_ne2(T const & a, U const & b) +{ + BOOST_TEST(!(a == b)); + +#ifndef BOOST_BROKEN_INEQUALITY + + BOOST_TEST(a != b); + +#endif + +} + int test_main(int, char * []) { using namespace boost; @@ -94,6 +174,15 @@ int test_main(int, char * []) shared_ptr p(new Y); shared_ptr p2(new X); + test_is_Y(p); + test_is_X(p2); + test_ne(p, p2); + + { + shared_ptr q(p); + test_eq(p, q); + } + shared_ptr p3 = shared_dynamic_cast(p); shared_ptr p4 = shared_dynamic_cast(p2); @@ -102,8 +191,14 @@ int test_main(int, char * []) BOOST_TEST(p3.use_count() == 2); BOOST_TEST(p4.use_count() == 1); + test_is_Y(p3); + test_eq2(p, p3); + test_ne2(p2, p4); + shared_ptr p5(p); + test_eq2(p, p5); + std::cout << "--\n"; p.reset(); @@ -125,14 +220,20 @@ int test_main(int, char * []) BOOST_TEST(wp2.use_count() == 1); BOOST_TEST(wp2.get() != 0); + test_is_Y(wp2); + test_ne(wp1, wp2); + weak_ptr wp3 = shared_dynamic_cast(wp2); BOOST_TEST(wp3.use_count() == 1); BOOST_TEST(wp3.get() != 0); - BOOST_TEST(wp2 == wp3); + + test_eq2(wp2, wp3); weak_ptr wp4(wp3); + test_eq(wp2, wp4); + wp1 = p2; wp1 = p4; wp1 = wp3; @@ -140,7 +241,13 @@ int test_main(int, char * []) BOOST_TEST(wp1.use_count() == 1); BOOST_TEST(wp1.get() != 0); - BOOST_TEST(wp1 == wp2); + + test_eq(wp1, wp2); + + weak_ptr wp5; + + bool b1 = wp1 < wp5; + bool b2 = wp5 < wp1; p5.reset(); @@ -153,6 +260,12 @@ int test_main(int, char * []) BOOST_TEST(wp3.use_count() == 0); BOOST_TEST(wp3.get() == 0); + // Test operator< stability for std::set< weak_ptr<> > + // Thanks to Joe Gottman for pointing this out + + BOOST_TEST(b1 == (wp1 < wp5)); + BOOST_TEST(b2 == (wp5 < wp1)); + shared_ptr p6(get_object(), release_object); }