From f6fc17d2e545a13da5acb82aa2f2eb22c9f4ce35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Dee=20=28J=C5=8Dshin=29?= Date: Wed, 28 Aug 2024 11:31:00 -0700 Subject: [PATCH] Add bad_weak_ptr case --- ctl/shared_ptr.h | 19 ++++++++++++++++++- test/ctl/shared_ptr_test.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/ctl/shared_ptr.h b/ctl/shared_ptr.h index 4553c2f99..cc31cf231 100644 --- a/ctl/shared_ptr.h +++ b/ctl/shared_ptr.h @@ -4,6 +4,7 @@ #define CTL_SHARED_PTR_H_ #include "conditional.h" +#include "exception.h" #include "is_convertible.h" #include "is_void.h" #include "remove_extent.h" @@ -11,6 +12,15 @@ namespace ctl { +class bad_weak_ptr : public exception +{ + public: + const char* what() const noexcept override + { + return "ctl::bad_weak_ptr"; + } +}; + namespace __ { static inline __attribute__((always_inline)) void @@ -217,8 +227,12 @@ class shared_ptr template requires is_convertible_v - explicit shared_ptr(const weak_ptr& r) : shared_ptr(r.lock()) + explicit shared_ptr(const weak_ptr& r) : p(r.p), rc(r.rc) { + if (r.expired()) { + throw bad_weak_ptr(); + } + rc->keep_shared(); } // TODO(mrdomino): blocked on ctl::ref @@ -408,6 +422,9 @@ class weak_ptr } private: + template + friend class shared_ptr; + element_type* p = nullptr; __::shared_ref* rc = nullptr; }; diff --git a/test/ctl/shared_ptr_test.cc b/test/ctl/shared_ptr_test.cc index 359739ebe..c8cf3f536 100644 --- a/test/ctl/shared_ptr_test.cc +++ b/test/ctl/shared_ptr_test.cc @@ -36,6 +36,8 @@ make_shared(Args&&... args) return ctl::make_shared(ctl::forward(args)...); } +using bad_weak_ptr = ctl::bad_weak_ptr; + #undef ctl static int g = 0; @@ -215,6 +217,32 @@ main() return 20; } + { + // Expired weak pointers lock to nullptr, and throw when promoted to + // shared pointer by constructor. + auto x = make_shared(); + weak_ptr y(x); + x.reset(); + if (y.lock()) + return 21; + int caught = 0; + try { + shared_ptr z(y); + } catch (bad_weak_ptr& e) { + caught = 1; + } + if (!caught) + return 22; + } + + { + // nullptr is always expired. + shared_ptr x(nullptr); + weak_ptr y(x); + if (!y.expired()) + return 23; + } + // TODO(mrdomino): exercise threads / races. The reference count should be // atomically maintained.