From Jason Turner

[smartptr.adapt]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpzusq7x74/{from.md → to.md} +358 -0
tmp/tmpzusq7x74/{from.md → to.md} RENAMED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Smart pointer adaptors <a id="smartptr.adapt">[[smartptr.adapt]]</a>
2
+
3
+ #### Class template `out_ptr_t` <a id="out.ptr.t">[[out.ptr.t]]</a>
4
+
5
+ `out_ptr_t` is a class template used to adapt types such as smart
6
+ pointers [[smartptr]] for functions that use output pointer parameters.
7
+
8
+ [*Example 1*:
9
+
10
+ ``` cpp
11
+ #include <memory>
12
+ #include <cstdio>
13
+
14
+ int fopen_s(std::FILE** f, const char* name, const char* mode);
15
+
16
+ struct fclose_deleter {
17
+ void operator()(std::FILE* f) const noexcept {
18
+ std::fclose(f);
19
+ }
20
+ };
21
+
22
+ int main(int, char*[]) {
23
+ constexpr const char* file_name = "ow.o";
24
+ std::unique_ptr<std::FILE, fclose_deleter> file_ptr;
25
+ int err = fopen_s(std::out_ptr<std::FILE*>(file_ptr), file_name, "r+b");
26
+ if (err != 0)
27
+ return 1;
28
+ // *file_ptr is valid
29
+ return 0;
30
+ }
31
+ ```
32
+
33
+ `unique_ptr` can be used with `out_ptr` to be passed into an output
34
+ pointer-style function, without needing to hold onto an intermediate
35
+ pointer value and manually delete it on error or failure.
36
+
37
+ — *end example*]
38
+
39
+ ``` cpp
40
+ namespace std {
41
+ template<class Smart, class Pointer, class... Args>
42
+ class out_ptr_t {
43
+ public:
44
+ explicit out_ptr_t(Smart&, Args...);
45
+ out_ptr_t(const out_ptr_t&) = delete;
46
+
47
+ ~out_ptr_t();
48
+
49
+ operator Pointer*() const noexcept;
50
+ operator void**() const noexcept;
51
+
52
+ private:
53
+ Smart& s; // exposition only
54
+ tuple<Args...> a; // exposition only
55
+ Pointer p; // exposition only
56
+ };
57
+ }
58
+ ```
59
+
60
+ `Pointer` shall meet the *Cpp17NullablePointer* requirements. If `Smart`
61
+ is a specialization of `shared_ptr` and `sizeof...(Args) == 0`, the
62
+ program is ill-formed.
63
+
64
+ [*Note 1*: It is typically a user error to reset a `shared_ptr` without
65
+ specifying a deleter, as `shared_ptr` will replace a custom deleter upon
66
+ usage of `reset`, as specified in
67
+ [[util.smartptr.shared.mod]]. — *end note*]
68
+
69
+ Program-defined specializations of `out_ptr_t` that depend on at least
70
+ one program-defined type need not meet the requirements for the primary
71
+ template.
72
+
73
+ Evaluations of the conversion functions on the same object may conflict
74
+ [[intro.races]].
75
+
76
+ ``` cpp
77
+ explicit out_ptr_t(Smart& smart, Args... args);
78
+ ```
79
+
80
+ *Effects:* Initializes `s` with `smart`, `a` with
81
+ `std::forward<Args>(args)...`, and value-initializes `p`. Then,
82
+ equivalent to:
83
+
84
+ - ``` cpp
85
+ s.reset();
86
+ ```
87
+
88
+ if the expression `s.reset()` is well-formed;
89
+
90
+ - otherwise,
91
+ ``` cpp
92
+ s = Smart();
93
+ ```
94
+
95
+ if `is_constructible_v<Smart>` is `true`;
96
+
97
+ - otherwise, the program is ill-formed.
98
+
99
+ [*Note 1*: The constructor is not `noexcept` to allow for a variety of
100
+ non-terminating and safe implementation strategies. For example, an
101
+ implementation can allocate a `shared_ptr`’s internal node in the
102
+ constructor and let implementation-defined exceptions escape safely. The
103
+ destructor can then move the allocated control block in directly and
104
+ avoid any other exceptions. — *end note*]
105
+
106
+ ``` cpp
107
+ ~out_ptr_t();
108
+ ```
109
+
110
+ Let `SP` be *`POINTER_OF_OR`*`(Smart, Pointer)` [[memory.general]].
111
+
112
+ *Effects:* Equivalent to:
113
+
114
+ -
115
+ ``` cpp
116
+ if (p) {
117
+ apply([&](auto&&... args) {
118
+ s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
119
+ }
120
+ ```
121
+
122
+ if the expression
123
+ `s.reset(static_cast<SP>(p), std::forward<Args>(args)...)` is
124
+ well-formed;
125
+ - otherwise,
126
+ ``` cpp
127
+ if (p) {
128
+ apply([&](auto&&... args) {
129
+ s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
130
+ }
131
+ ```
132
+
133
+ if `is_constructible_v<Smart, SP, Args...>` is `true`;
134
+ - otherwise, the program is ill-formed.
135
+
136
+ ``` cpp
137
+ operator Pointer*() const noexcept;
138
+ ```
139
+
140
+ *Preconditions:* `operator void**()` has not been called on `*this`.
141
+
142
+ *Returns:* `addressof(const_cast<Pointer&>(p))`.
143
+
144
+ ``` cpp
145
+ operator void**() const noexcept;
146
+ ```
147
+
148
+ *Constraints:* `is_same_v<Pointer, void*>` is `false`.
149
+
150
+ *Mandates:* `is_pointer_v<Pointer>` is `true`.
151
+
152
+ *Preconditions:* `operator Pointer*()` has not been called on `*this`.
153
+
154
+ *Returns:* A pointer value `v` such that:
155
+
156
+ - the initial value `*v` is equivalent to `static_cast<void*>(p)` and
157
+ - any modification of `*v` that is not followed by a subsequent
158
+ modification of `*this` affects the value of `p` during the
159
+ destruction of `*this`, such that `static_cast<void*>(p) == *v`.
160
+
161
+ *Remarks:* Accessing `*v` outside the lifetime of `*this` has undefined
162
+ behavior.
163
+
164
+ [*Note 2*: `reinterpret_cast<void**>(static_cast<Pointer*>(*this))` can
165
+ be a viable implementation strategy for some
166
+ implementations. — *end note*]
167
+
168
+ #### Function template `out_ptr` <a id="out.ptr">[[out.ptr]]</a>
169
+
170
+ ``` cpp
171
+ template<class Pointer = void, class Smart, class... Args>
172
+ auto out_ptr(Smart& s, Args&&... args);
173
+ ```
174
+
175
+ Let `P` be `Pointer` if `is_void_v<Pointer>` is `false`, otherwise
176
+ *`POINTER_OF`*`(Smart)`.
177
+
178
+ *Returns:*
179
+ `out_ptr_t<Smart, P, Args&&...>(s, std::forward<Args>(args)...)`
180
+
181
+ #### Class template `inout_ptr_t` <a id="inout.ptr.t">[[inout.ptr.t]]</a>
182
+
183
+ `inout_ptr_t` is a class template used to adapt types such as smart
184
+ pointers [[smartptr]] for functions that use output pointer parameters
185
+ whose dereferenced values may first be deleted before being set to
186
+ another allocated value.
187
+
188
+ [*Example 1*:
189
+
190
+ ``` cpp
191
+ #include <memory>
192
+
193
+ struct star_fish* star_fish_alloc();
194
+ int star_fish_populate(struct star_fish** ps, const char* description);
195
+
196
+ struct star_fish_deleter {
197
+ void operator() (struct star_fish* c) const noexcept;
198
+ };
199
+
200
+ using star_fish_ptr = std::unique_ptr<star_fish, star_fish_deleter>;
201
+
202
+ int main(int, char*[]) {
203
+ star_fish_ptr peach(star_fish_alloc());
204
+ // ...
205
+ // used, need to re-make
206
+ int err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker");
207
+ return err;
208
+ }
209
+ ```
210
+
211
+ A `unique_ptr` can be used with `inout_ptr` to be passed into an output
212
+ pointer-style function. The original value will be properly deleted
213
+ according to the function it is used with and a new value reset in its
214
+ place.
215
+
216
+ — *end example*]
217
+
218
+ ``` cpp
219
+ namespace std {
220
+ template<class Smart, class Pointer, class... Args>
221
+ class inout_ptr_t {
222
+ public:
223
+ explicit inout_ptr_t(Smart&, Args...);
224
+ inout_ptr_t(const inout_ptr_t&) = delete;
225
+
226
+ ~inout_ptr_t();
227
+
228
+ operator Pointer*() const noexcept;
229
+ operator void**() const noexcept;
230
+
231
+ private:
232
+ Smart& s; // exposition only
233
+ tuple<Args...> a; // exposition only
234
+ Pointer p; // exposition only
235
+ };
236
+ }
237
+ ```
238
+
239
+ `Pointer` shall meet the *Cpp17NullablePointer* requirements. If `Smart`
240
+ is a specialization of `shared_ptr`, the program is ill-formed.
241
+
242
+ [*Note 1*: It is impossible to properly acquire unique ownership of the
243
+ managed resource from a `shared_ptr` given its shared ownership
244
+ model. — *end note*]
245
+
246
+ Program-defined specializations of `inout_ptr_t` that depend on at least
247
+ one program-defined type need not meet the requirements for the primary
248
+ template.
249
+
250
+ Evaluations of the conversion functions on the same object may conflict
251
+ [[intro.races]].
252
+
253
+ ``` cpp
254
+ explicit inout_ptr_t(Smart& smart, Args... args);
255
+ ```
256
+
257
+ *Effects:* Initializes `s` with `smart`, `a` with
258
+ `std::forward<Args>(args)...`, and `p` to either
259
+
260
+ - `smart` if `is_pointer_v<Smart>` is `true`,
261
+ - otherwise, `smart.get()`.
262
+
263
+ *Remarks:* An implementation can call `s.release()`.
264
+
265
+ [*Note 1*: The constructor is not `noexcept` to allow for a variety of
266
+ non-terminating and safe implementation strategies. For example, an
267
+ intrusive pointer implementation with a control block can allocate in
268
+ the constructor and safely fail with an exception. — *end note*]
269
+
270
+ ``` cpp
271
+ ~inout_ptr_t();
272
+ ```
273
+
274
+ Let `SP` be *`POINTER_OF_OR`*`(Smart, Pointer)` [[memory.general]].
275
+
276
+ Let *release-statement* be `s.release();` if an implementation does not
277
+ call `s.release()` in the constructor. Otherwise, it is empty.
278
+
279
+ *Effects:* Equivalent to:
280
+
281
+ -
282
+ ``` cpp
283
+ if (p) {
284
+ apply([&](auto&&... args) {
285
+ s = Smart( static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
286
+ }
287
+ ```
288
+
289
+ if `is_pointer_v<Smart>` is `true`;
290
+ - otherwise,
291
+ ``` cpp
292
+ release-statement;
293
+ if (p) {
294
+ apply([&](auto&&... args) {
295
+ s.reset(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
296
+ }
297
+ ```
298
+
299
+ if the expression
300
+ `s.reset(static_cast<SP>(p), std::forward<Args>(args)...)` is well-
301
+ formed;
302
+ - otherwise,
303
+ ``` cpp
304
+ release-statement;
305
+ if (p) {
306
+ apply([&](auto&&... args) {
307
+ s = Smart(static_cast<SP>(p), std::forward<Args>(args)...); }, std::move(a));
308
+ }
309
+ ```
310
+
311
+ if `is_constructible_v<Smart, SP, Args...>` is `true`;
312
+ - otherwise, the program is ill-formed.
313
+
314
+ ``` cpp
315
+ operator Pointer*() const noexcept;
316
+ ```
317
+
318
+ *Preconditions:* `operator void**()` has not been called on `*this`.
319
+
320
+ *Returns:* `addressof(const_cast<Pointer&>(p))`.
321
+
322
+ ``` cpp
323
+ operator void**() const noexcept;
324
+ ```
325
+
326
+ *Constraints:* `is_same_v<Pointer, void*>` is `false`.
327
+
328
+ *Mandates:* `is_pointer_v<Pointer>` is `true`.
329
+
330
+ *Preconditions:* `operator Pointer*()` has not been called on `*this`.
331
+
332
+ *Returns:* A pointer value `v` such that:
333
+
334
+ - the initial value `*v` is equivalent to `static_cast<void*>(p)` and
335
+ - any modification of `*v` that is not followed by subsequent
336
+ modification of `*this` affects the value of `p` during the
337
+ destruction of `*this`, such that `static_cast<void*>(p) == *v`.
338
+
339
+ *Remarks:* Accessing `*v` outside the lifetime of `*this` has undefined
340
+ behavior.
341
+
342
+ [*Note 2*: `reinterpret_cast<void**>(static_cast<Pointer*>(*this))` can
343
+ be a viable implementation strategy for some
344
+ implementations. — *end note*]
345
+
346
+ #### Function template `inout_ptr` <a id="inout.ptr">[[inout.ptr]]</a>
347
+
348
+ ``` cpp
349
+ template<class Pointer = void, class Smart, class... Args>
350
+ auto inout_ptr(Smart& s, Args&&... args);
351
+ ```
352
+
353
+ Let `P` be `Pointer` if `is_void_v<Pointer>` is `false`, otherwise
354
+ *`POINTER_OF`*`(Smart)`.
355
+
356
+ *Returns:*
357
+ `inout_ptr_t<Smart, P, Args&&...>(s, std::forward<Args>(args)...)`.
358
+