From 929fb1ad5d7cbdeb23843f8973845f290e336e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Dee=20=28J=C5=8Dshin=29?= Date: Sat, 15 Jun 2024 21:37:29 -0700 Subject: [PATCH] Minor unique_ptr cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly value-initializes the deleter, even though I have not found a way to get the deleter to act like it’s been default-initialized in unit tests so far. Uses auto in reset. The static cast is apparently not needed (unless I’m missing some case I didn’t think of.) Tests Base/Derived reset. Implements the general move constructor - turns out that the reason this didn’t work before was that default_delete was not move constructible from default_delete. Drop inline specifiers from functions defined entirely inside the struct definition since they are implicitly inline. Adds some constexpr declarations to default_delete. Adds default_delete specialization for T[]. Makes parameters const. --- ctl/unique_ptr.h | 71 ++++++++++++++++++++++--------------- test/ctl/unique_ptr_test.cc | 14 ++++++++ 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/ctl/unique_ptr.h b/ctl/unique_ptr.h index 179beda12..da2ed0710 100644 --- a/ctl/unique_ptr.h +++ b/ctl/unique_ptr.h @@ -2,6 +2,7 @@ // vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi #ifndef COSMOPOLITAN_CTL_UNIQUE_PTR_H_ #define COSMOPOLITAN_CTL_UNIQUE_PTR_H_ +#include <__type_traits/is_convertible.h> #include <__utility/forward.h> #include <__utility/move.h> #include <__utility/swap.h> @@ -11,12 +12,31 @@ namespace ctl { template struct default_delete { - constexpr void operator()(T* p) const noexcept + constexpr default_delete() noexcept = default; + template + constexpr default_delete(default_delete&&) noexcept + { + } + constexpr void operator()(T* const p) const noexcept { delete p; } }; +template +struct default_delete +{ + constexpr default_delete() noexcept = default; + template + constexpr default_delete(default_delete&&) noexcept + { + } + constexpr void operator()(T* const p) const noexcept + { + delete[] p; + } +}; + template> struct unique_ptr { @@ -27,102 +47,97 @@ struct unique_ptr pointer p; [[no_unique_address]] deleter_type d; - constexpr unique_ptr(nullptr_t = nullptr) noexcept : p(nullptr) + constexpr unique_ptr(const nullptr_t = nullptr) noexcept : p(nullptr), d() { } - constexpr unique_ptr(pointer p) noexcept : p(p) + constexpr unique_ptr(const pointer p) noexcept : p(p), d() { } - constexpr unique_ptr(pointer p, auto&& d) noexcept + constexpr unique_ptr(auto* const p, auto&& d) noexcept : p(p), d(std::forward(d)) { } - constexpr unique_ptr(unique_ptr&& u) noexcept : p(u.p), d(std::move(u.d)) + template + requires std::is_convertible_v && std::is_convertible_v + constexpr unique_ptr(unique_ptr&& u) noexcept + : p(u.p), d(std::move(u.d)) { u.p = nullptr; } - // TODO(mrdomino): - // template - // unique_ptr(unique_ptr&& u) noexcept; - unique_ptr(const unique_ptr&) = delete; - inline ~unique_ptr() /* noexcept */ + ~unique_ptr() /* noexcept */ { reset(); } - inline unique_ptr& operator=(unique_ptr r) noexcept + unique_ptr& operator=(unique_ptr r) noexcept { swap(r); return *this; } - inline pointer release() noexcept + pointer release() noexcept { pointer r = p; p = nullptr; return r; } - inline void reset(nullptr_t = nullptr) noexcept + void reset(const nullptr_t = nullptr) noexcept { if (p) d(p); p = nullptr; } - template - // TODO(mrdomino): - /* requires is_convertible_v */ - inline void reset(U* p2) + void reset(auto* const p2) { if (p) { d(p); } - p = static_cast(p2); + p = p2; } - inline void swap(unique_ptr& r) noexcept + void swap(unique_ptr& r) noexcept { using std::swap; swap(p, r.p); swap(d, r.d); } - inline pointer get() const noexcept + pointer get() const noexcept { return p; } - inline deleter_type& get_deleter() noexcept + deleter_type& get_deleter() noexcept { return d; } - inline const deleter_type& get_deleter() const noexcept + const deleter_type& get_deleter() const noexcept { return d; } - inline explicit operator bool() const noexcept + explicit operator bool() const noexcept { return p; } - inline element_type& operator*() const - noexcept(noexcept(*std::declval())) + element_type& operator*() const noexcept(noexcept(*std::declval())) { if (!p) __builtin_trap(); return *p; } - inline pointer operator->() const noexcept + pointer operator->() const noexcept { if (!p) __builtin_trap(); @@ -131,14 +146,14 @@ struct unique_ptr }; template -inline unique_ptr +unique_ptr make_unique(Args&&... args) { return unique_ptr(new T(std::forward(args)...)); } template -inline unique_ptr +unique_ptr make_unique_for_overwrite() { #if 0 diff --git a/test/ctl/unique_ptr_test.cc b/test/ctl/unique_ptr_test.cc index 4d6699b25..d1e860bc1 100644 --- a/test/ctl/unique_ptr_test.cc +++ b/test/ctl/unique_ptr_test.cc @@ -91,6 +91,12 @@ struct SetsGDtor } }; +struct Base +{}; + +struct Derived : Base +{}; + int main() { @@ -211,6 +217,14 @@ main() Ptr y(&a); } + { + Ptr x(new Base); + x.reset(new Derived); + + Ptr y(new Derived); + Ptr z(std::move(y)); + } + // next is 18 return 0;