Skip to content

Commit d7b1919

Browse files
authored
ctl::unique_ptr improvements and cleanup (#1221)
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.) Implements the general move constructor - turns out that the reason this didn’t work before was that default_delete<U> was not move constructible from default_delete<T>. Drop inline specifiers from functions defined entirely inside the struct definition since they are implicitly inline. * Cleans up reset to match spec Remove the variants from the T[] specialization. Also follow the spec on the order of operations in reset, which may matter if we are deleting an object that has a reference to the unique_ptr that is being reset. (?) * Tests Base/Derived reset. * Adds some constexpr declarations. * Adds default_delete specialization for T[]. * Makes parameters const.
1 parent f86e6f8 commit d7b1919

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

ctl/unique_ptr.h

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,38 @@
33
#ifndef COSMOPOLITAN_CTL_UNIQUE_PTR_H_
44
#define COSMOPOLITAN_CTL_UNIQUE_PTR_H_
55
#include "utility.h"
6+
#include <__type_traits/is_convertible.h>
67

78
namespace ctl {
89

910
template<typename T>
1011
struct default_delete
1112
{
12-
constexpr void operator()(T* p) const noexcept
13+
constexpr default_delete() noexcept = default;
14+
template<typename U>
15+
constexpr default_delete(default_delete<U>&&) noexcept
16+
{
17+
}
18+
constexpr void operator()(T* const p) const noexcept
1319
{
1420
delete p;
1521
}
1622
};
1723

24+
template<typename T>
25+
struct default_delete<T[]>
26+
{
27+
constexpr default_delete() noexcept = default;
28+
template<typename U>
29+
constexpr default_delete(default_delete<U>&&) noexcept
30+
{
31+
}
32+
constexpr void operator()(T* const p) const noexcept
33+
{
34+
delete[] p;
35+
}
36+
};
37+
1838
template<typename T, typename D = default_delete<T>>
1939
struct unique_ptr
2040
{
@@ -25,102 +45,91 @@ struct unique_ptr
2545
pointer p;
2646
[[no_unique_address]] deleter_type d;
2747

28-
constexpr unique_ptr(nullptr_t = nullptr) noexcept : p(nullptr)
48+
constexpr unique_ptr(const nullptr_t = nullptr) noexcept : p(nullptr), d()
2949
{
3050
}
3151

32-
constexpr unique_ptr(pointer p) noexcept : p(p)
52+
constexpr unique_ptr(const pointer p) noexcept : p(p), d()
3353
{
3454
}
3555

36-
constexpr unique_ptr(pointer p, auto&& d) noexcept
56+
constexpr unique_ptr(const pointer p, auto&& d) noexcept
3757
: p(p), d(ctl::forward<decltype(d)>(d))
3858
{
3959
}
4060

41-
constexpr unique_ptr(unique_ptr&& u) noexcept : p(u.p), d(ctl::move(u.d))
61+
template<typename U, typename E>
62+
requires std::is_convertible_v<U, T> && std::is_convertible_v<E, D>
63+
constexpr unique_ptr(unique_ptr<U, E>&& u) noexcept
64+
: p(u.p), d(ctl::move(u.d))
4265
{
4366
u.p = nullptr;
4467
}
4568

46-
// TODO(mrdomino):
47-
// template <typename U, typename E>
48-
// unique_ptr(unique_ptr<U, E>&& u) noexcept;
49-
5069
unique_ptr(const unique_ptr&) = delete;
5170

52-
inline ~unique_ptr() /* noexcept */
71+
constexpr ~unique_ptr() /* noexcept */
5372
{
54-
reset();
73+
if (p)
74+
d(p);
5575
}
5676

57-
inline unique_ptr& operator=(unique_ptr r) noexcept
77+
constexpr unique_ptr& operator=(unique_ptr r) noexcept
5878
{
5979
swap(r);
6080
return *this;
6181
}
6282

63-
inline pointer release() noexcept
83+
constexpr pointer release() noexcept
6484
{
6585
pointer r = p;
6686
p = nullptr;
6787
return r;
6888
}
6989

70-
inline void reset(nullptr_t = nullptr) noexcept
90+
constexpr void reset(const pointer p2 = pointer()) noexcept
7191
{
72-
if (p)
73-
d(p);
74-
p = nullptr;
75-
}
76-
77-
template<typename U>
78-
// TODO(mrdomino):
79-
/* requires is_convertible_v<U, T> */
80-
inline void reset(U* p2)
81-
{
82-
if (p) {
83-
d(p);
84-
}
85-
p = static_cast<pointer>(p2);
92+
const pointer r = p;
93+
p = p2;
94+
if (r)
95+
d(r);
8696
}
8797

88-
inline void swap(unique_ptr& r) noexcept
98+
constexpr void swap(unique_ptr& r) noexcept
8999
{
90100
using ctl::swap;
91101
swap(p, r.p);
92102
swap(d, r.d);
93103
}
94104

95-
inline pointer get() const noexcept
105+
constexpr pointer get() const noexcept
96106
{
97107
return p;
98108
}
99109

100-
inline deleter_type& get_deleter() noexcept
110+
constexpr deleter_type& get_deleter() noexcept
101111
{
102112
return d;
103113
}
104114

105-
inline const deleter_type& get_deleter() const noexcept
115+
constexpr const deleter_type& get_deleter() const noexcept
106116
{
107117
return d;
108118
}
109119

110-
inline explicit operator bool() const noexcept
120+
constexpr explicit operator bool() const noexcept
111121
{
112122
return p;
113123
}
114124

115-
inline element_type& operator*() const
116-
noexcept(noexcept(*ctl::declval<pointer>()))
125+
element_type& operator*() const noexcept(noexcept(*ctl::declval<pointer>()))
117126
{
118127
if (!p)
119128
__builtin_trap();
120129
return *p;
121130
}
122131

123-
inline pointer operator->() const noexcept
132+
pointer operator->() const noexcept
124133
{
125134
if (!p)
126135
__builtin_trap();
@@ -129,14 +138,14 @@ struct unique_ptr
129138
};
130139

131140
template<typename T, typename... Args>
132-
inline unique_ptr<T>
141+
constexpr unique_ptr<T>
133142
make_unique(Args&&... args)
134143
{
135144
return unique_ptr<T>(new T(ctl::forward<Args>(args)...));
136145
}
137146

138147
template<typename T>
139-
inline unique_ptr<T>
148+
constexpr unique_ptr<T>
140149
make_unique_for_overwrite()
141150
{
142151
#if 0

test/ctl/unique_ptr_test.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ struct SetsGDtor
9191
}
9292
};
9393

94+
struct Base
95+
{};
96+
97+
struct Derived : Base
98+
{};
99+
94100
int
95101
main()
96102
{
@@ -211,7 +217,16 @@ main()
211217
Ptr<int, StatefulDeleter> y(&a);
212218
}
213219

220+
{
221+
Ptr<Base> x(new Base);
222+
x.reset(new Derived);
223+
224+
Ptr<Derived> y(new Derived);
225+
Ptr<Base> z(ctl::move(y));
226+
}
227+
214228
// next is 18
215229

230+
CheckForMemoryLeaks();
216231
return 0;
217232
}

0 commit comments

Comments
 (0)