Skip to content

Commit

Permalink
weak_ptr: Make it possible to convert to "compatible" pointers
Browse files Browse the repository at this point in the history
The patch introduces weak_ptr<T>(weak_ptr<Y>&&) constructor that creates
weak_ptr<T> 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<base> out of weak_ptr<inherited>.

Signed-off-by: Pavel Emelyanov <[email protected]>
  • Loading branch information
xemul authored and avikivity committed May 16, 2024
1 parent 97aa247 commit 0ad9d82
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
17 changes: 17 additions & 0 deletions include/seastar/core/weak_ptr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ template<typename T>
class weak_ptr {
template<typename U>
friend class weakly_referencable;
template <typename U>
friend class weak_ptr;
private:
using hook_type = boost::intrusive::list_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
hook_type _hook;
Expand All @@ -59,7 +61,18 @@ private:
_hook.swap_nodes(o._hook);
std::swap(_ptr, o._ptr);
}

public:
template <typename U>
requires std::convertible_to<U*, T*>
weak_ptr(weak_ptr<U>&& 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
Expand Down Expand Up @@ -139,6 +152,10 @@ public:
_ptr_list.push_back(ptr);
return ptr;
}

weak_ptr<const T> weak_from_this() const noexcept {
return const_cast<weakly_referencable*>(this)->weak_from_this();
}
};

}
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/weak_ptr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<myclass>();

weak_ptr<const myclass> cwptr = const_cast<const myclass&>(*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<myiclass> {};

BOOST_AUTO_TEST_CASE(test_base_class_weak_ptr) {
auto owning_ptr = std::make_unique<myiclass>();

auto get_checker = [] (weak_ptr<baseclass> 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<myclass>();
weak_ptr<myclass> wp1 = owning_ptr->weak_from_this();
Expand Down

0 comments on commit 0ad9d82

Please sign in to comment.