From bf67047980a0053a9915dd056a1b7867675be56b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 7 May 2024 12:56:05 +0300 Subject: [PATCH] weak_ptr: Make it possible to convert to "compatible" pointers The patch introduces weak_ptr(weak_ptr&&) constructor that creates weak_ptr out of convertible to T* Y's. This has two implications. First, the main one, is that it's now possible to obtain a constant weak pointer on an object. Another, a nice side effect, is: given a base-class we can now create weak_ptr out of weak_ptr. Signed-off-by: Pavel Emelyanov --- include/seastar/core/weak_ptr.hh | 17 +++++++++++++++++ tests/unit/weak_ptr_test.cc | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/seastar/core/weak_ptr.hh b/include/seastar/core/weak_ptr.hh index f73d936efed..98fe32d96a3 100644 --- a/include/seastar/core/weak_ptr.hh +++ b/include/seastar/core/weak_ptr.hh @@ -46,6 +46,8 @@ template class weak_ptr { template friend class weakly_referencable; + template + friend class weak_ptr; private: using hook_type = boost::intrusive::list_member_hook>; hook_type _hook; @@ -59,7 +61,18 @@ private: _hook.swap_nodes(o._hook); std::swap(_ptr, o._ptr); } + public: + template + requires std::convertible_to + weak_ptr(weak_ptr&& o) + { + if (o._ptr) { + _ptr = std::exchange(o._ptr, nullptr); + _hook.swap_nodes(o._hook); + } + } + // Note: The default constructor's body is implemented as no-op // rather than `noexcept = default` due to a bug with gcc 9.3.1 // that deletes the constructor since boost::intrusive::list_member_hook @@ -139,6 +152,10 @@ public: _ptr_list.push_back(ptr); return ptr; } + + weak_ptr weak_from_this() const noexcept { + return const_cast(this)->weak_from_this(); + } }; } diff --git a/tests/unit/weak_ptr_test.cc b/tests/unit/weak_ptr_test.cc index 5929a2a60a6..7d2f863f129 100644 --- a/tests/unit/weak_ptr_test.cc +++ b/tests/unit/weak_ptr_test.cc @@ -48,6 +48,33 @@ BOOST_AUTO_TEST_CASE(test_weak_ptr_is_reset) { BOOST_REQUIRE(!bool(wp)); } +BOOST_AUTO_TEST_CASE(test_const_weak_ptr) { + auto owning_ptr = std::make_unique(); + + weak_ptr cwptr = const_cast(*owning_ptr).weak_from_this(); + BOOST_REQUIRE(bool(cwptr)); + owning_ptr.reset(); + BOOST_REQUIRE(!bool(cwptr)); +} + +class baseclass {}; +class myiclass : public baseclass, public weakly_referencable {}; + +BOOST_AUTO_TEST_CASE(test_base_class_weak_ptr) { + auto owning_ptr = std::make_unique(); + + auto get_checker = [] (weak_ptr p) { + return [p = std::move(p)] (bool v) { + BOOST_REQUIRE_EQUAL(bool(p), v); + }; + }; + + auto checker = get_checker(owning_ptr->weak_from_this()); + checker(true); + owning_ptr.reset(); + checker(false); +} + BOOST_AUTO_TEST_CASE(test_weak_ptr_can_be_moved) { auto owning_ptr = std::make_unique(); weak_ptr wp1 = owning_ptr->weak_from_this();