24
24
// #include <type_traits>
25
25
// #define ctl std
26
26
27
- template <typename T, typename D = ctl::default_delete<T>>
28
- using Ptr = ctl::unique_ptr<T, D>;
27
+ using ctl::unique_ptr;
28
+ using ctl::make_unique;
29
+ using ctl::make_unique_for_overwrite;
29
30
30
- template <typename T, typename ... Args>
31
- Ptr<T>
32
- Mk (Args&&... args)
33
- {
34
- return ctl::make_unique<T, Args...>(ctl::forward<Args>(args)...);
35
- }
36
-
37
- template <typename T>
38
- Ptr<T>
39
- MkRaw ()
40
- {
41
- return ctl::make_unique_for_overwrite<T>();
42
- }
43
-
44
- // #undef ctl
31
+ #undef ctl
45
32
33
+ // The following few definitions are used to get observability into aspects of
34
+ // an object's lifecycle, to make sure that e.g. constructing a unique_ptr of a
35
+ // type does not construct an object, and that make_unique does construct an
36
+ // object.
46
37
static int g = 0 ;
47
38
48
- struct SetsGDeleter
39
+ struct ConstructG
49
40
{
50
- void operator ()( auto * x) const noexcept
41
+ ConstructG ()
51
42
{
52
43
++g;
53
- delete x;
54
44
}
55
45
};
56
46
57
- struct StatefulDeleter
47
+ struct DestructG
58
48
{
59
- char state;
60
- void operator ()(auto * x) const noexcept
49
+ ~DestructG ()
61
50
{
51
+ ++g;
62
52
}
63
53
};
64
54
65
- struct FinalDeleter final
55
+ struct CallG
66
56
{
67
57
void operator ()(auto * x) const noexcept
68
58
{
59
+ ++g;
69
60
}
70
61
};
71
62
72
- static_assert (sizeof (Ptr<int , SetsGDeleter>) == sizeof(int *));
73
-
74
- // not everyone uses [[no_unique_address]]...
75
- static_assert (!ctl::is_same_v<Ptr<int >, ctl::unique_ptr<int >> ||
76
- sizeof (Ptr<int , FinalDeleter>) == sizeof(int *));
63
+ // A unique_ptr with an empty deleter should be the same size as a raw pointer.
64
+ static_assert (sizeof (unique_ptr<int , decltype ([] {})>) == sizeof(int *));
77
65
78
- struct SetsGCtor
66
+ struct FinalDeleter final
79
67
{
80
- SetsGCtor ()
68
+ void operator ()( auto * x) const noexcept
81
69
{
82
- ++g;
83
70
}
84
71
};
85
72
86
- struct SetsGDtor
87
- {
88
- ~SetsGDtor ()
89
- {
90
- ++g;
91
- }
92
- };
73
+ // ctl::unique_ptr does not need to inherit from its deleter for this property;
74
+ // the STL often does, though, so we don't hold them to the following.
75
+ static_assert (!ctl::is_same_v<unique_ptr<int >, ctl::unique_ptr<int >> ||
76
+ sizeof (unique_ptr<int , FinalDeleter>) == sizeof(int *));
93
77
94
78
struct Base
95
79
{};
@@ -100,36 +84,62 @@ struct Derived : Base
100
84
int
101
85
main ()
102
86
{
87
+ int a;
103
88
104
89
{
105
- Ptr<int > x (new int (5 ));
90
+ // Shouldn't cause any memory leaks.
91
+ unique_ptr<int > x (new int (5 ));
106
92
}
107
93
108
94
{
109
- Ptr<int , SetsGDeleter> x (new int ());
95
+ // Deleter is called if the pointer is non-null when reset.
96
+ unique_ptr<int , CallG> x (&a);
110
97
x.reset ();
111
98
if (g != 1 )
112
99
return 1 ;
113
100
}
114
101
115
102
{
116
103
g = 0 ;
117
- Ptr<int , SetsGDeleter> x (new int ());
118
- delete x.release ();
104
+ // Deleter is not called if the pointer is null when reset.
105
+ unique_ptr<int , CallG> x (&a);
106
+ x.release ();
119
107
x.reset ();
120
108
if (g)
121
109
return 17 ;
122
110
}
123
111
124
112
{
125
- Ptr<int > x (new int (5 )), y (new int (6 ));
113
+ g = 0 ;
114
+ // Deleter is called when the pointer goes out of scope.
115
+ {
116
+ unique_ptr<int , CallG> x (&a);
117
+ }
118
+ if (!g)
119
+ return 18 ;
120
+ }
121
+
122
+ {
123
+ g = 0 ;
124
+ // Deleter is called if scope ends exceptionally.
125
+ try {
126
+ unique_ptr<int , CallG> x (&a);
127
+ throw ' a' ;
128
+ } catch (char ) {
129
+ }
130
+ if (!g)
131
+ return 19 ;
132
+ }
133
+
134
+ {
135
+ unique_ptr<int > x (new int (5 )), y (new int (6 ));
126
136
x.swap (y);
127
137
if (*x != 6 || *y != 5 )
128
138
return 2 ;
129
139
}
130
140
131
141
{
132
- Ptr <int > x;
142
+ unique_ptr <int > x;
133
143
if (x)
134
144
return 3 ;
135
145
x.reset (new int (5 ));
@@ -139,17 +149,17 @@ main()
139
149
140
150
{
141
151
g = 0 ;
142
- Ptr<SetsGCtor > x;
152
+ unique_ptr<ConstructG > x;
143
153
if (g)
144
154
return 5 ;
145
- x = Mk<SetsGCtor >();
155
+ x = make_unique<ConstructG >();
146
156
if (g != 1 )
147
157
return 6 ;
148
158
}
149
159
150
160
{
151
161
g = 0 ;
152
- auto x = Mk<SetsGDtor >();
162
+ auto x = make_unique<DestructG >();
153
163
if (g)
154
164
return 7 ;
155
165
x.reset ();
@@ -161,9 +171,9 @@ main()
161
171
162
172
{
163
173
g = 0 ;
164
- Ptr<SetsGDtor > x, y;
165
- x = Mk<SetsGDtor >();
166
- y = Mk<SetsGDtor >();
174
+ unique_ptr<DestructG > x, y;
175
+ x = make_unique<DestructG >();
176
+ y = make_unique<DestructG >();
167
177
#if 0
168
178
// shouldn't compile
169
179
x = y;
@@ -178,7 +188,7 @@ main()
178
188
{
179
189
g = 0 ;
180
190
{
181
- auto x = Mk<SetsGDtor >();
191
+ auto x = make_unique<DestructG >();
182
192
}
183
193
if (g != 1 )
184
194
return 12 ;
@@ -187,7 +197,7 @@ main()
187
197
{
188
198
g = 0 ;
189
199
{
190
- auto x = Mk<SetsGDtor >();
200
+ auto x = make_unique<DestructG >();
191
201
delete x.release ();
192
202
}
193
203
if (g != 1 )
@@ -199,13 +209,13 @@ main()
199
209
// side effects it has are illegal to detect?
200
210
{
201
211
g = 0;
202
- auto x = MkRaw <DefaultInitialized>();
212
+ auto x = make_unique_for_overwrite <DefaultInitialized>();
203
213
if (g)
204
214
return 14;
205
215
x.reset();
206
216
if (g)
207
217
return 15;
208
- x = Mk <DefaultInitialized>();
218
+ x = make_unique <DefaultInitialized>();
209
219
if (g != 1)
210
220
return 16;
211
221
}
@@ -214,16 +224,15 @@ main()
214
224
{
215
225
int a;
216
226
// Should compile.
217
- Ptr<int , FinalDeleter> x (&a);
218
- Ptr<int , StatefulDeleter> y (&a);
227
+ unique_ptr<int , FinalDeleter> x (&a);
219
228
}
220
229
221
230
{
222
- Ptr <Base> x (new Base);
231
+ unique_ptr <Base> x (new Base);
223
232
x.reset (new Derived);
224
233
225
- Ptr <Derived> y (new Derived);
226
- Ptr <Base> z (ctl::move (y));
234
+ unique_ptr <Derived> y (new Derived);
235
+ unique_ptr <Base> z (ctl::move (y));
227
236
}
228
237
229
238
CheckForMemoryLeaks ();
0 commit comments