From Jason Turner

[mem.res]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpunw6faay/{from.md → to.md} +164 -220
tmp/tmpunw6faay/{from.md → to.md} RENAMED
@@ -6,21 +6,17 @@
6
  namespace std::pmr {
7
  // [mem.res.class], class memory_resource
8
  class memory_resource;
9
 
10
  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
11
- bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;
12
 
13
  // [mem.poly.allocator.class], class template polymorphic_allocator
14
  template<class Tp> class polymorphic_allocator;
15
 
16
  template<class T1, class T2>
17
  bool operator==(const polymorphic_allocator<T1>& a,
18
  const polymorphic_allocator<T2>& b) noexcept;
19
- template <class T1, class T2>
20
- bool operator!=(const polymorphic_allocator<T1>& a,
21
- const polymorphic_allocator<T2>& b) noexcept;
22
 
23
  // [mem.res.global], global memory resources
24
  memory_resource* new_delete_resource() noexcept;
25
  memory_resource* null_memory_resource() noexcept;
26
  memory_resource* set_default_resource(memory_resource* r) noexcept;
@@ -38,80 +34,84 @@ namespace std::pmr {
38
 
39
  The `memory_resource` class is an abstract interface to an unbounded set
40
  of classes encapsulating memory resources.
41
 
42
  ``` cpp
 
43
  class memory_resource {
44
  static constexpr size_t max_align = alignof(max_align_t); // exposition only
45
 
46
  public:
 
 
47
  virtual ~memory_resource();
48
 
49
- void* allocate(size_t bytes, size_t alignment = max_align);
 
 
50
  void deallocate(void* p, size_t bytes, size_t alignment = max_align);
51
 
52
  bool is_equal(const memory_resource& other) const noexcept;
53
 
54
  private:
55
  virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
56
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
57
 
58
  virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
59
  };
 
60
  ```
61
 
62
- #### `memory_resource` public member functions <a id="mem.res.public">[[mem.res.public]]</a>
63
 
64
  ``` cpp
65
  ~memory_resource();
66
  ```
67
 
68
  *Effects:* Destroys this `memory_resource`.
69
 
70
  ``` cpp
71
- void* allocate(size_t bytes, size_t alignment = max_align);
72
  ```
73
 
74
  *Effects:* Equivalent to: `return do_allocate(bytes, alignment);`
75
 
76
  ``` cpp
77
  void deallocate(void* p, size_t bytes, size_t alignment = max_align);
78
  ```
79
 
80
- *Effects:* Equivalent to: `do_deallocate(p, bytes, alignment);`
81
 
82
  ``` cpp
83
  bool is_equal(const memory_resource& other) const noexcept;
84
  ```
85
 
86
  *Effects:* Equivalent to: `return do_is_equal(other);`
87
 
88
- #### `memory_resource` private virtual member functions <a id="mem.res.private">[[mem.res.private]]</a>
89
 
90
  ``` cpp
91
  virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
92
  ```
93
 
94
- *Requires:* `alignment` shall be a power of two.
95
 
96
  *Returns:* A derived class shall implement this function to return a
97
- pointer to allocated storage ([[basic.stc.dynamic.deallocation]]) with
98
- a size of at least `bytes`. The returned storage is aligned to the
99
- specified alignment, if such alignment is supported ([[basic.align]]);
100
- otherwise it is aligned to `max_align`.
101
 
102
  *Throws:* A derived class implementation shall throw an appropriate
103
  exception if it is unable to allocate memory with the requested size and
104
  alignment.
105
 
106
  ``` cpp
107
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
108
  ```
109
 
110
- *Requires:* `p` shall have been returned from a prior call to
111
  `allocate(bytes, alignment)` on a memory resource equal to `*this`, and
112
- the storage at `p` shall not yet have been deallocated.
113
 
114
  *Effects:* A derived class shall implement this function to dispose of
115
  allocated storage.
116
 
117
  *Throws:* Nothing.
@@ -123,42 +123,40 @@ virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
123
  *Returns:* A derived class shall implement this function to return
124
  `true` if memory allocated from `this` can be deallocated from `other`
125
  and vice-versa, otherwise `false`.
126
 
127
  [*Note 1*: The most-derived type of `other` might not match the type of
128
- `this`. For a derived class `D`, a typical implementation of this
129
- function will immediately return `false` if
130
  `dynamic_cast<const D*>(&other) == nullptr`. — *end note*]
131
 
132
- #### `memory_resource` equality <a id="mem.res.eq">[[mem.res.eq]]</a>
133
 
134
  ``` cpp
135
  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
136
  ```
137
 
138
  *Returns:* `&a == &b || a.is_equal(b)`.
139
 
140
- ``` cpp
141
- bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;
142
- ```
143
-
144
- *Returns:* `!(a == b)`.
145
-
146
  ### Class template `polymorphic_allocator` <a id="mem.poly.allocator.class">[[mem.poly.allocator.class]]</a>
147
 
148
- A specialization of class template `pmr::polymorphic_allocator` conforms
149
- to the `Allocator` requirements ([[allocator.requirements]]).
150
- Constructed with different memory resources, different instances of the
151
- same specialization of `pmr::polymorphic_allocator` can exhibit entirely
152
  different allocation behavior. This runtime polymorphism allows objects
153
  that use `polymorphic_allocator` to behave as if they used different
154
  allocator types at run time even though they use the same static
155
  allocator type.
156
 
 
 
 
 
157
  ``` cpp
158
- template <class Tp>
159
- class polymorphic_allocator {
160
  memory_resource* memory_rsrc; // exposition only
161
 
162
  public:
163
  using value_type = Tp;
164
 
@@ -169,42 +167,37 @@ public:
169
  polymorphic_allocator(const polymorphic_allocator& other) = default;
170
 
171
  template<class U>
172
  polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
173
 
174
- polymorphic_allocator&
175
- operator=(const polymorphic_allocator& rhs) = delete;
176
 
177
  // [mem.poly.allocator.mem], member functions
178
- Tp* allocate(size_t n);
179
  void deallocate(Tp* p, size_t n);
180
 
 
 
 
 
 
 
 
181
  template<class T, class... Args>
182
  void construct(T* p, Args&&... args);
183
 
184
- template <class T1, class T2, class... Args1, class... Args2>
185
- void construct(pair<T1,T2>* p, piecewise_construct_t,
186
- tuple<Args1...> x, tuple<Args2...> y);
187
- template <class T1, class T2>
188
- void construct(pair<T1,T2>* p);
189
- template <class T1, class T2, class U, class V>
190
- void construct(pair<T1,T2>* p, U&& x, V&& y);
191
- template <class T1, class T2, class U, class V>
192
- void construct(pair<T1,T2>* p, const pair<U, V>& pr);
193
- template <class T1, class T2, class U, class V>
194
- void construct(pair<T1,T2>* p, pair<U, V>&& pr);
195
-
196
  template<class T>
197
  void destroy(T* p);
198
 
199
  polymorphic_allocator select_on_container_copy_construction() const;
200
 
201
  memory_resource* resource() const;
202
  };
 
203
  ```
204
 
205
- #### `polymorphic_allocator` constructors <a id="mem.poly.allocator.ctor">[[mem.poly.allocator.ctor]]</a>
206
 
207
  ``` cpp
208
  polymorphic_allocator() noexcept;
209
  ```
210
 
@@ -212,171 +205,143 @@ polymorphic_allocator() noexcept;
212
 
213
  ``` cpp
214
  polymorphic_allocator(memory_resource* r);
215
  ```
216
 
217
- *Requires:* `r` is non-null.
218
 
219
  *Effects:* Sets `memory_rsrc` to `r`.
220
 
221
  *Throws:* Nothing.
222
 
223
  [*Note 1*: This constructor provides an implicit conversion from
224
  `memory_resource*`. — *end note*]
225
 
226
  ``` cpp
227
- template <class U>
228
- polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
229
  ```
230
 
231
  *Effects:* Sets `memory_rsrc` to `other.resource()`.
232
 
233
- #### `polymorphic_allocator` member functions <a id="mem.poly.allocator.mem">[[mem.poly.allocator.mem]]</a>
234
 
235
  ``` cpp
236
- Tp* allocate(size_t n);
237
  ```
238
 
239
- *Returns:* Equivalent to
 
240
 
241
  ``` cpp
242
  return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
243
  ```
244
 
245
  ``` cpp
246
  void deallocate(Tp* p, size_t n);
247
  ```
248
 
249
- *Requires:* `p` was allocated from a memory resource `x`, equal to
250
  `*memory_rsrc`, using `x.allocate(n * sizeof(Tp), alignof(Tp))`.
251
 
252
  *Effects:* Equivalent to
253
  `memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))`.
254
 
255
  *Throws:* Nothing.
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  ``` cpp
258
  template<class T, class... Args>
259
  void construct(T* p, Args&&... args);
260
  ```
261
 
262
- *Requires:* Uses-allocator construction of `T` with allocator
263
- `resource()` (see  [[allocator.uses.construction]]) and constructor
264
- arguments `std::forward<Args>(args)...` is well-formed.
265
-
266
- [*Note 1*: Uses-allocator construction is always well formed for types
267
- that do not use allocators. — *end note*]
268
 
269
  *Effects:* Construct a `T` object in the storage whose address is
270
- represented by `p` by uses-allocator construction with allocator
271
- `resource()` and constructor arguments `std::forward<Args>(args)...`.
272
 
273
  *Throws:* Nothing unless the constructor for `T` throws.
274
 
275
- ``` cpp
276
- template <class T1, class T2, class... Args1, class... Args2>
277
- void construct(pair<T1,T2>* p, piecewise_construct_t,
278
- tuple<Args1...> x, tuple<Args2...> y);
279
- ```
280
-
281
- [*Note 2*: This method and the `construct` methods that follow are
282
- overloads for piecewise construction of
283
- pairs ([[pairs.pair]]). — *end note*]
284
-
285
- *Effects:* Let `xprime` be a `tuple` constructed from `x` according to
286
- the appropriate rule from the following list.
287
-
288
- [*Note 3*: The following description can be summarized as constructing
289
- a `pair<T1, T2>` object in the storage whose address is represented by
290
- `p`, as if by separate uses-allocator construction with allocator
291
- `resource()` ([[allocator.uses.construction]]) of `p->first` using the
292
- elements of `x` and `p->second` using the elements of
293
- `y`. — *end note*]
294
-
295
- - If `uses_allocator_v<T1,memory_resource*>` is `false`
296
- and `is_constructible_v<T1,Args1...>` is `true`,
297
- then `xprime` is `x`.
298
- - Otherwise, if `uses_allocator_v<T1,memory_resource*>` is `true`
299
- and `is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...>`
300
- is `true`,
301
- then `xprime` is
302
- `tuple_cat(make_tuple(allocator_arg, resource()), std::move(x))`.
303
- - Otherwise, if `uses_allocator_v<T1,memory_resource*>` is `true`
304
- and `is_constructible_v<T1,Args1...,memory_resource*>` is `true`,
305
- then `xprime` is `tuple_cat(std::move(x), make_tuple(resource()))`.
306
- - Otherwise the program is ill formed.
307
-
308
- Let `yprime` be a tuple constructed from `y` according to the
309
- appropriate rule from the following list:
310
-
311
- - If `uses_allocator_v<T2,memory_resource*>` is `false`
312
- and `is_constructible_v<T2,Args2...>` is `true`,
313
- then `yprime` is `y`.
314
- - Otherwise, if `uses_allocator_v<T2,memory_resource*>` is `true`
315
- and `is_constructible_v<T2,allocator_arg_t,memory_resource*,Args2...>`
316
- is `true`,
317
- then `yprime` is
318
- `tuple_cat(make_tuple(allocator_arg, resource()), std::move(y))`.
319
- - Otherwise, if `uses_allocator_v<T2,memory_resource*>` is `true`
320
- and `is_constructible_v<T2,Args2...,memory_resource*>` is `true`,
321
- then `yprime` is `tuple_cat(std::move(y), make_tuple(resource()))`.
322
- - Otherwise the program is ill formed.
323
-
324
- Then, using `piecewise_construct`, `xprime`, and `yprime` as the
325
- constructor arguments, this function constructs a `pair<T1, T2>` object
326
- in the storage whose address is represented by `p`.
327
-
328
- ``` cpp
329
- template <class T1, class T2>
330
- void construct(pair<T1,T2>* p);
331
- ```
332
-
333
- *Effects:* Equivalent to:
334
-
335
- ``` cpp
336
- construct(p, piecewise_construct, tuple<>(), tuple<>());
337
- ```
338
-
339
- ``` cpp
340
- template <class T1, class T2, class U, class V>
341
- void construct(pair<T1,T2>* p, U&& x, V&& y);
342
- ```
343
-
344
- *Effects:* Equivalent to:
345
-
346
- ``` cpp
347
- construct(p, piecewise_construct,
348
- forward_as_tuple(std::forward<U>(x)),
349
- forward_as_tuple(std::forward<V>(y)));
350
- ```
351
-
352
- ``` cpp
353
- template <class T1, class T2, class U, class V>
354
- void construct(pair<T1,T2>* p, const pair<U, V>& pr);
355
- ```
356
-
357
- *Effects:* Equivalent to:
358
-
359
- ``` cpp
360
- construct(p, piecewise_construct,
361
- forward_as_tuple(pr.first),
362
- forward_as_tuple(pr.second));
363
- ```
364
-
365
- ``` cpp
366
- template <class T1, class T2, class U, class V>
367
- void construct(pair<T1,T2>* p, pair<U, V>&& pr);
368
- ```
369
-
370
- *Effects:* Equivalent to:
371
-
372
- ``` cpp
373
- construct(p, piecewise_construct,
374
- forward_as_tuple(std::forward<U>(pr.first)),
375
- forward_as_tuple(std::forward<V>(pr.second)));
376
- ```
377
-
378
  ``` cpp
379
  template<class T>
380
  void destroy(T* p);
381
  ```
382
 
@@ -394,28 +359,20 @@ polymorphic_allocator select_on_container_copy_construction() const;
394
  memory_resource* resource() const;
395
  ```
396
 
397
  *Returns:* `memory_rsrc`.
398
 
399
- #### `polymorphic_allocator` equality <a id="mem.poly.allocator.eq">[[mem.poly.allocator.eq]]</a>
400
 
401
  ``` cpp
402
  template<class T1, class T2>
403
  bool operator==(const polymorphic_allocator<T1>& a,
404
  const polymorphic_allocator<T2>& b) noexcept;
405
  ```
406
 
407
  *Returns:* `*a.resource() == *b.resource()`.
408
 
409
- ``` cpp
410
- template <class T1, class T2>
411
- bool operator!=(const polymorphic_allocator<T1>& a,
412
- const polymorphic_allocator<T2>& b) noexcept;
413
- ```
414
-
415
- *Returns:* `!(a == b)`.
416
-
417
  ### Access to program-wide `memory_resource` objects <a id="mem.res.global">[[mem.res.global]]</a>
418
 
419
  ``` cpp
420
  memory_resource* new_delete_resource() noexcept;
421
  ```
@@ -447,12 +404,10 @@ memory_resource* set_default_resource(memory_resource* r) noexcept;
447
 
448
  *Effects:* If `r` is non-null, sets the value of the default memory
449
  resource pointer to `r`, otherwise sets the default memory resource
450
  pointer to `new_delete_resource()`.
451
 
452
- *Postconditions:* `get_default_resource() == r`.
453
-
454
  *Returns:* The previous value of the default memory resource pointer.
455
 
456
  *Remarks:* Calling the `set_default_resource` and `get_default_resource`
457
  functions shall not incur a data race. A call to the
458
  `set_default_resource` function shall synchronize with subsequent calls
@@ -498,19 +453,19 @@ without external synchronization and may have thread-specific pools to
498
  reduce synchronization costs. An `unsynchronized_pool_resource` class
499
  may not be accessed from multiple threads simultaneously and thus avoids
500
  the cost of synchronization entirely in single-threaded applications.
501
 
502
  ``` cpp
 
503
  struct pool_options {
504
  size_t max_blocks_per_chunk = 0;
505
  size_t largest_required_pool_block = 0;
506
  };
507
 
508
  class synchronized_pool_resource : public memory_resource {
509
  public:
510
- synchronized_pool_resource(const pool_options& opts,
511
- memory_resource* upstream);
512
 
513
  synchronized_pool_resource()
514
  : synchronized_pool_resource(pool_options(), get_default_resource()) {}
515
  explicit synchronized_pool_resource(memory_resource* upstream)
516
  : synchronized_pool_resource(pool_options(), upstream) {}
@@ -518,12 +473,11 @@ public:
518
  : synchronized_pool_resource(opts, get_default_resource()) {}
519
 
520
  synchronized_pool_resource(const synchronized_pool_resource&) = delete;
521
  virtual ~synchronized_pool_resource();
522
 
523
- synchronized_pool_resource&
524
- operator=(const synchronized_pool_resource&) = delete;
525
 
526
  void release();
527
  memory_resource* upstream_resource() const;
528
  pool_options options() const;
529
 
@@ -534,12 +488,11 @@ protected:
534
  bool do_is_equal(const memory_resource& other) const noexcept override;
535
  };
536
 
537
  class unsynchronized_pool_resource : public memory_resource {
538
  public:
539
- unsynchronized_pool_resource(const pool_options& opts,
540
- memory_resource* upstream);
541
 
542
  unsynchronized_pool_resource()
543
  : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
544
  explicit unsynchronized_pool_resource(memory_resource* upstream)
545
  : unsynchronized_pool_resource(pool_options(), upstream) {}
@@ -547,12 +500,11 @@ public:
547
  : unsynchronized_pool_resource(opts, get_default_resource()) {}
548
 
549
  unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
550
  virtual ~unsynchronized_pool_resource();
551
 
552
- unsynchronized_pool_resource&
553
- operator=(const unsynchronized_pool_resource&) = delete;
554
 
555
  void release();
556
  memory_resource* upstream_resource() const;
557
  pool_options options() const;
558
 
@@ -560,10 +512,11 @@ protected:
560
  void* do_allocate(size_t bytes, size_t alignment) override;
561
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;
562
 
563
  bool do_is_equal(const memory_resource& other) const noexcept override;
564
  };
 
565
  ```
566
 
567
  #### `pool_options` data members <a id="mem.res.pool.options">[[mem.res.pool.options]]</a>
568
 
569
  The members of `pool_options` comprise a set of constructor options for
@@ -573,11 +526,11 @@ is described below:
573
  ``` cpp
574
  size_t max_blocks_per_chunk;
575
  ```
576
 
577
  The maximum number of blocks that will be allocated at once from the
578
- upstream memory resource ([[mem.res.monotonic.buffer]]) to replenish a
579
  pool. If the value of `max_blocks_per_chunk` is zero or is greater than
580
  an *implementation-defined* limit, that limit is used instead. The
581
  implementation may choose to use a smaller value than is specified in
582
  this field and may use different values for different pools.
583
 
@@ -591,18 +544,18 @@ threshold will be allocated directly from the upstream memory resource.
591
  If `largest_required_pool_block` is zero or is greater than an
592
  *implementation-defined* limit, that limit is used instead. The
593
  implementation may choose a pass-through threshold larger than specified
594
  in this field.
595
 
596
- #### Pool resource constructors and destructors <a id="mem.res.pool.ctor">[[mem.res.pool.ctor]]</a>
597
 
598
  ``` cpp
599
  synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
600
  unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
601
  ```
602
 
603
- *Requires:* `upstream` is the address of a valid memory resource.
604
 
605
  *Effects:* Constructs a pool resource object that will obtain memory
606
  from `upstream` whenever the pool resource is unable to satisfy a memory
607
  request from its own internal data structures. The resulting object will
608
  hold a copy of `upstream`, but will not own the resource to which
@@ -624,11 +577,11 @@ virtual ~synchronized_pool_resource();
624
  virtual ~unsynchronized_pool_resource();
625
  ```
626
 
627
  *Effects:* Calls `release()`.
628
 
629
- #### Pool resource members <a id="mem.res.pool.mem">[[mem.res.pool.mem]]</a>
630
 
631
  ``` cpp
632
  void release();
633
  ```
634
 
@@ -658,14 +611,15 @@ rounded to unspecified granularity.
658
 
659
  ``` cpp
660
  void* do_allocate(size_t bytes, size_t alignment) override;
661
  ```
662
 
663
- *Returns:* A pointer to allocated storage
664
- ([[basic.stc.dynamic.deallocation]]) with a size of at least `bytes`.
665
- The size and alignment of the allocated memory shall meet the
666
- requirements for a class derived from `memory_resource` ([[mem.res]]).
 
667
 
668
  *Effects:* If the pool selected for a block of size `bytes` is unable to
669
  satisfy the memory request from its own internal data structures, it
670
  will call `upstream_resource()->allocate()` to obtain more memory. If
671
  `bytes` is larger than that which the largest pool can handle, then
@@ -682,24 +636,14 @@ or under what circumstances, this operation will result in a call to
682
  `upstream_resource()->deallocate()`.
683
 
684
  *Throws:* Nothing.
685
 
686
  ``` cpp
687
- bool synchronized_pool_resource::do_is_equal(
688
- const memory_resource& other) const noexcept override;
689
  ```
690
 
691
- *Returns:*
692
- `this == dynamic_cast<const synchronized_pool_resource*>(&other)`.
693
-
694
- ``` cpp
695
- bool unsynchronized_pool_resource::do_is_equal(
696
- const memory_resource& other) const noexcept override;
697
- ```
698
-
699
- *Returns:*
700
- `this == dynamic_cast<const unsynchronized_pool_resource*>(&other)`.
701
 
702
  ### Class `monotonic_buffer_resource` <a id="mem.res.monotonic.buffer">[[mem.res.monotonic.buffer]]</a>
703
 
704
  A `monotonic_buffer_resource` is a special-purpose memory resource
705
  intended for very fast memory allocations in situations where memory is
@@ -719,20 +663,20 @@ memory resource object is destroyed. It has the following qualities:
719
  with one another.
720
  - It frees the allocated memory on destruction, even if `deallocate` has
721
  not been called for some of the allocated blocks.
722
 
723
  ``` cpp
 
724
  class monotonic_buffer_resource : public memory_resource {
725
  memory_resource* upstream_rsrc; // exposition only
726
  void* current_buffer; // exposition only
727
  size_t next_buffer_size; // exposition only
728
 
729
  public:
730
  explicit monotonic_buffer_resource(memory_resource* upstream);
731
  monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
732
- monotonic_buffer_resource(void *buffer, size_t buffer_size,
733
- memory_resource *upstream);
734
 
735
  monotonic_buffer_resource()
736
  : monotonic_buffer_resource(get_default_resource()) {}
737
  explicit monotonic_buffer_resource(size_t initial_size)
738
  : monotonic_buffer_resource(initial_size, get_default_resource()) {}
@@ -741,45 +685,45 @@ public:
741
 
742
  monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
743
 
744
  virtual ~monotonic_buffer_resource();
745
 
746
- monotonic_buffer_resource
747
- operator=(const monotonic_buffer_resource&) = delete;
748
 
749
  void release();
750
  memory_resource* upstream_resource() const;
751
 
752
  protected:
753
  void* do_allocate(size_t bytes, size_t alignment) override;
754
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;
755
 
756
  bool do_is_equal(const memory_resource& other) const noexcept override;
757
  };
 
758
  ```
759
 
760
- #### `monotonic_buffer_resource` constructor and destructor <a id="mem.res.monotonic.buffer.ctor">[[mem.res.monotonic.buffer.ctor]]</a>
761
 
762
  ``` cpp
763
  explicit monotonic_buffer_resource(memory_resource* upstream);
764
  monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
765
  ```
766
 
767
- *Requires:* `upstream` shall be the address of a valid memory resource.
768
- `initial_size`, if specified, shall be greater than zero.
769
 
770
  *Effects:* Sets `upstream_rsrc` to `upstream` and `current_buffer` to
771
  `nullptr`. If `initial_size` is specified, sets `next_buffer_size` to at
772
  least `initial_size`; otherwise sets `next_buffer_size` to an
773
  *implementation-defined* size.
774
 
775
  ``` cpp
776
  monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
777
  ```
778
 
779
- *Requires:* `upstream` shall be the address of a valid memory resource.
780
- `buffer_size` shall be no larger than the number of bytes in `buffer`.
781
 
782
  *Effects:* Sets `upstream_rsrc` to `upstream`, `current_buffer` to
783
  `buffer`, and `next_buffer_size` to `buffer_size` (but not less than 1),
784
  then increases `next_buffer_size` by an *implementation-defined* growth
785
  factor (which need not be integral).
@@ -788,11 +732,11 @@ factor (which need not be integral).
788
  ~monotonic_buffer_resource();
789
  ```
790
 
791
  *Effects:* Calls `release()`.
792
 
793
- #### `monotonic_buffer_resource` members <a id="mem.res.monotonic.buffer.mem">[[mem.res.monotonic.buffer.mem]]</a>
794
 
795
  ``` cpp
796
  void release();
797
  ```
798
 
@@ -811,14 +755,15 @@ memory_resource* upstream_resource() const;
811
 
812
  ``` cpp
813
  void* do_allocate(size_t bytes, size_t alignment) override;
814
  ```
815
 
816
- *Returns:* A pointer to allocated storage
817
- ([[basic.stc.dynamic.deallocation]]) with a size of at least `bytes`.
818
- The size and alignment of the allocated memory shall meet the
819
- requirements for a class derived from `memory_resource` ([[mem.res]]).
 
820
 
821
  *Effects:* If the unused space in `current_buffer` can fit a block with
822
  the specified `bytes` and `alignment`, then allocate the return block
823
  from `current_buffer`; otherwise set `current_buffer` to
824
  `upstream_rsrc->allocate(n, m)`, where `n` is not less than
@@ -842,8 +787,7 @@ its destruction.
842
 
843
  ``` cpp
844
  bool do_is_equal(const memory_resource& other) const noexcept override;
845
  ```
846
 
847
- *Returns:*
848
- `this == dynamic_cast<const monotonic_buffer_resource*>(&other)`.
849
 
 
6
  namespace std::pmr {
7
  // [mem.res.class], class memory_resource
8
  class memory_resource;
9
 
10
  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
 
11
 
12
  // [mem.poly.allocator.class], class template polymorphic_allocator
13
  template<class Tp> class polymorphic_allocator;
14
 
15
  template<class T1, class T2>
16
  bool operator==(const polymorphic_allocator<T1>& a,
17
  const polymorphic_allocator<T2>& b) noexcept;
 
 
 
18
 
19
  // [mem.res.global], global memory resources
20
  memory_resource* new_delete_resource() noexcept;
21
  memory_resource* null_memory_resource() noexcept;
22
  memory_resource* set_default_resource(memory_resource* r) noexcept;
 
34
 
35
  The `memory_resource` class is an abstract interface to an unbounded set
36
  of classes encapsulating memory resources.
37
 
38
  ``` cpp
39
+ namespace std::pmr {
40
  class memory_resource {
41
  static constexpr size_t max_align = alignof(max_align_t); // exposition only
42
 
43
  public:
44
+ memory_resource() = default;
45
+ memory_resource(const memory_resource&) = default;
46
  virtual ~memory_resource();
47
 
48
+ memory_resource& operator=(const memory_resource&) = default;
49
+
50
+ [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
51
  void deallocate(void* p, size_t bytes, size_t alignment = max_align);
52
 
53
  bool is_equal(const memory_resource& other) const noexcept;
54
 
55
  private:
56
  virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
57
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
58
 
59
  virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
60
  };
61
+ }
62
  ```
63
 
64
+ #### Public member functions <a id="mem.res.public">[[mem.res.public]]</a>
65
 
66
  ``` cpp
67
  ~memory_resource();
68
  ```
69
 
70
  *Effects:* Destroys this `memory_resource`.
71
 
72
  ``` cpp
73
+ [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
74
  ```
75
 
76
  *Effects:* Equivalent to: `return do_allocate(bytes, alignment);`
77
 
78
  ``` cpp
79
  void deallocate(void* p, size_t bytes, size_t alignment = max_align);
80
  ```
81
 
82
+ *Effects:* Equivalent to `do_deallocate(p, bytes, alignment)`.
83
 
84
  ``` cpp
85
  bool is_equal(const memory_resource& other) const noexcept;
86
  ```
87
 
88
  *Effects:* Equivalent to: `return do_is_equal(other);`
89
 
90
+ #### Private virtual member functions <a id="mem.res.private">[[mem.res.private]]</a>
91
 
92
  ``` cpp
93
  virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
94
  ```
95
 
96
+ *Preconditions:* `alignment` is a power of two.
97
 
98
  *Returns:* A derived class shall implement this function to return a
99
+ pointer to allocated storage [[basic.stc.dynamic.allocation]] with a
100
+ size of at least `bytes`, aligned to the specified `alignment`.
 
 
101
 
102
  *Throws:* A derived class implementation shall throw an appropriate
103
  exception if it is unable to allocate memory with the requested size and
104
  alignment.
105
 
106
  ``` cpp
107
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
108
  ```
109
 
110
+ *Preconditions:* `p` was returned from a prior call to
111
  `allocate(bytes, alignment)` on a memory resource equal to `*this`, and
112
+ the storage at `p` has not yet been deallocated.
113
 
114
  *Effects:* A derived class shall implement this function to dispose of
115
  allocated storage.
116
 
117
  *Throws:* Nothing.
 
123
  *Returns:* A derived class shall implement this function to return
124
  `true` if memory allocated from `this` can be deallocated from `other`
125
  and vice-versa, otherwise `false`.
126
 
127
  [*Note 1*: The most-derived type of `other` might not match the type of
128
+ `this`. For a derived class `D`, an implementation of this function
129
+ could immediately return `false` if
130
  `dynamic_cast<const D*>(&other) == nullptr`. — *end note*]
131
 
132
+ #### Equality <a id="mem.res.eq">[[mem.res.eq]]</a>
133
 
134
  ``` cpp
135
  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
136
  ```
137
 
138
  *Returns:* `&a == &b || a.is_equal(b)`.
139
 
 
 
 
 
 
 
140
  ### Class template `polymorphic_allocator` <a id="mem.poly.allocator.class">[[mem.poly.allocator.class]]</a>
141
 
142
+ A specialization of class template `pmr::polymorphic_allocator` meets
143
+ the *Cpp17Allocator* requirements ([[cpp17.allocator]]). Constructed
144
+ with different memory resources, different instances of the same
145
+ specialization of `pmr::polymorphic_allocator` can exhibit entirely
146
  different allocation behavior. This runtime polymorphism allows objects
147
  that use `polymorphic_allocator` to behave as if they used different
148
  allocator types at run time even though they use the same static
149
  allocator type.
150
 
151
+ All specializations of class template `pmr::polymorphic_allocator` meet
152
+ the allocator completeness requirements
153
+ [[allocator.requirements.completeness]].
154
+
155
  ``` cpp
156
+ namespace std::pmr {
157
+ template<class Tp = byte> class polymorphic_allocator {
158
  memory_resource* memory_rsrc; // exposition only
159
 
160
  public:
161
  using value_type = Tp;
162
 
 
167
  polymorphic_allocator(const polymorphic_allocator& other) = default;
168
 
169
  template<class U>
170
  polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
171
 
172
+ polymorphic_allocator& operator=(const polymorphic_allocator&) = delete;
 
173
 
174
  // [mem.poly.allocator.mem], member functions
175
+ [[nodiscard]] Tp* allocate(size_t n);
176
  void deallocate(Tp* p, size_t n);
177
 
178
+ [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t));
179
+ void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t));
180
+ template<class T> [[nodiscard]] T* allocate_object(size_t n = 1);
181
+ template<class T> void deallocate_object(T* p, size_t n = 1);
182
+ template<class T, class... CtorArgs> [[nodiscard]] T* new_object(CtorArgs&&... ctor_args);
183
+ template<class T> void delete_object(T* p);
184
+
185
  template<class T, class... Args>
186
  void construct(T* p, Args&&... args);
187
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  template<class T>
189
  void destroy(T* p);
190
 
191
  polymorphic_allocator select_on_container_copy_construction() const;
192
 
193
  memory_resource* resource() const;
194
  };
195
+ }
196
  ```
197
 
198
+ #### Constructors <a id="mem.poly.allocator.ctor">[[mem.poly.allocator.ctor]]</a>
199
 
200
  ``` cpp
201
  polymorphic_allocator() noexcept;
202
  ```
203
 
 
205
 
206
  ``` cpp
207
  polymorphic_allocator(memory_resource* r);
208
  ```
209
 
210
+ *Preconditions:* `r` is non-null.
211
 
212
  *Effects:* Sets `memory_rsrc` to `r`.
213
 
214
  *Throws:* Nothing.
215
 
216
  [*Note 1*: This constructor provides an implicit conversion from
217
  `memory_resource*`. — *end note*]
218
 
219
  ``` cpp
220
+ template<class U> polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
 
221
  ```
222
 
223
  *Effects:* Sets `memory_rsrc` to `other.resource()`.
224
 
225
+ #### Member functions <a id="mem.poly.allocator.mem">[[mem.poly.allocator.mem]]</a>
226
 
227
  ``` cpp
228
+ [[nodiscard]] Tp* allocate(size_t n);
229
  ```
230
 
231
+ *Effects:* If `numeric_limits<size_t>::max() / sizeof(Tp) < n`, throws
232
+ `bad_array_new_length`. Otherwise equivalent to:
233
 
234
  ``` cpp
235
  return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
236
  ```
237
 
238
  ``` cpp
239
  void deallocate(Tp* p, size_t n);
240
  ```
241
 
242
+ *Preconditions:* `p` was allocated from a memory resource `x`, equal to
243
  `*memory_rsrc`, using `x.allocate(n * sizeof(Tp), alignof(Tp))`.
244
 
245
  *Effects:* Equivalent to
246
  `memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))`.
247
 
248
  *Throws:* Nothing.
249
 
250
+ ``` cpp
251
+ [[nodiscard]] void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t));
252
+ ```
253
+
254
+ *Effects:* Equivalent to:
255
+ `return memory_rsrc->allocate(nbytes, alignment);`
256
+
257
+ [*Note 1*: The return type is `void*` (rather than, e.g., `byte*`) to
258
+ support conversion to an arbitrary pointer type `U*` by
259
+ `static_cast<U*>`, thus facilitating construction of a `U` object in the
260
+ allocated memory. — *end note*]
261
+
262
+ ``` cpp
263
+ void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t));
264
+ ```
265
+
266
+ *Effects:* Equivalent to
267
+ `memory_rsrc->deallocate(p, nbytes, alignment)`.
268
+
269
+ ``` cpp
270
+ template<class T>
271
+ [[nodiscard]] T* allocate_object(size_t n = 1);
272
+ ```
273
+
274
+ *Effects:* Allocates memory suitable for holding an array of `n` objects
275
+ of type `T`, as follows:
276
+
277
+ - if `numeric_limits<size_t>::max() / sizeof(T) < n`, throws
278
+ `bad_array_new_length`,
279
+ - otherwise equivalent to:
280
+ ``` cpp
281
+ return static_cast<T*>(allocate_bytes(n*sizeof(T), alignof(T)));
282
+ ```
283
+
284
+ [*Note 2*: `T` is not deduced and must therefore be provided as a
285
+ template argument. — *end note*]
286
+
287
+ ``` cpp
288
+ template<class T>
289
+ void deallocate_object(T* p, size_t n = 1);
290
+ ```
291
+
292
+ *Effects:* Equivalent to `deallocate_bytes(p, n*sizeof(T), alignof(T))`.
293
+
294
+ ``` cpp
295
+ template<class T, class CtorArgs...>
296
+ [[nodiscard]] T* new_object(CtorArgs&&... ctor_args);
297
+ ```
298
+
299
+ *Effects:* Allocates and constructs an object of type `T`, as follows.
300
+ Equivalent to:
301
+
302
+ ``` cpp
303
+ T* p = allocate_object<T>();
304
+ try {
305
+ construct(p, std::forward<CtorArgs>(ctor_args)...);
306
+ } catch (...) {
307
+ deallocate_object(p);
308
+ throw;
309
+ }
310
+ return p;
311
+ ```
312
+
313
+ [*Note 3*: `T` is not deduced and must therefore be provided as a
314
+ template argument. — *end note*]
315
+
316
+ ``` cpp
317
+ template<class T>
318
+ void delete_object(T* p);
319
+ ```
320
+
321
+ *Effects:* Equivalent to:
322
+
323
+ ``` cpp
324
+ destroy(p);
325
+ deallocate_object(p);
326
+ ```
327
+
328
  ``` cpp
329
  template<class T, class... Args>
330
  void construct(T* p, Args&&... args);
331
  ```
332
 
333
+ *Mandates:* Uses-allocator construction of `T` with allocator `*this`
334
+ (see  [[allocator.uses.construction]]) and constructor arguments
335
+ `std::forward<Args>(args)...` is well-formed.
 
 
 
336
 
337
  *Effects:* Construct a `T` object in the storage whose address is
338
+ represented by `p` by uses-allocator construction with allocator `*this`
339
+ and constructor arguments `std::forward<Args>(args)...`.
340
 
341
  *Throws:* Nothing unless the constructor for `T` throws.
342
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  ``` cpp
344
  template<class T>
345
  void destroy(T* p);
346
  ```
347
 
 
359
  memory_resource* resource() const;
360
  ```
361
 
362
  *Returns:* `memory_rsrc`.
363
 
364
+ #### Equality <a id="mem.poly.allocator.eq">[[mem.poly.allocator.eq]]</a>
365
 
366
  ``` cpp
367
  template<class T1, class T2>
368
  bool operator==(const polymorphic_allocator<T1>& a,
369
  const polymorphic_allocator<T2>& b) noexcept;
370
  ```
371
 
372
  *Returns:* `*a.resource() == *b.resource()`.
373
 
 
 
 
 
 
 
 
 
374
  ### Access to program-wide `memory_resource` objects <a id="mem.res.global">[[mem.res.global]]</a>
375
 
376
  ``` cpp
377
  memory_resource* new_delete_resource() noexcept;
378
  ```
 
404
 
405
  *Effects:* If `r` is non-null, sets the value of the default memory
406
  resource pointer to `r`, otherwise sets the default memory resource
407
  pointer to `new_delete_resource()`.
408
 
 
 
409
  *Returns:* The previous value of the default memory resource pointer.
410
 
411
  *Remarks:* Calling the `set_default_resource` and `get_default_resource`
412
  functions shall not incur a data race. A call to the
413
  `set_default_resource` function shall synchronize with subsequent calls
 
453
  reduce synchronization costs. An `unsynchronized_pool_resource` class
454
  may not be accessed from multiple threads simultaneously and thus avoids
455
  the cost of synchronization entirely in single-threaded applications.
456
 
457
  ``` cpp
458
+ namespace std::pmr {
459
  struct pool_options {
460
  size_t max_blocks_per_chunk = 0;
461
  size_t largest_required_pool_block = 0;
462
  };
463
 
464
  class synchronized_pool_resource : public memory_resource {
465
  public:
466
+ synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
 
467
 
468
  synchronized_pool_resource()
469
  : synchronized_pool_resource(pool_options(), get_default_resource()) {}
470
  explicit synchronized_pool_resource(memory_resource* upstream)
471
  : synchronized_pool_resource(pool_options(), upstream) {}
 
473
  : synchronized_pool_resource(opts, get_default_resource()) {}
474
 
475
  synchronized_pool_resource(const synchronized_pool_resource&) = delete;
476
  virtual ~synchronized_pool_resource();
477
 
478
+ synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete;
 
479
 
480
  void release();
481
  memory_resource* upstream_resource() const;
482
  pool_options options() const;
483
 
 
488
  bool do_is_equal(const memory_resource& other) const noexcept override;
489
  };
490
 
491
  class unsynchronized_pool_resource : public memory_resource {
492
  public:
493
+ unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
 
494
 
495
  unsynchronized_pool_resource()
496
  : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
497
  explicit unsynchronized_pool_resource(memory_resource* upstream)
498
  : unsynchronized_pool_resource(pool_options(), upstream) {}
 
500
  : unsynchronized_pool_resource(opts, get_default_resource()) {}
501
 
502
  unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
503
  virtual ~unsynchronized_pool_resource();
504
 
505
+ unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete;
 
506
 
507
  void release();
508
  memory_resource* upstream_resource() const;
509
  pool_options options() const;
510
 
 
512
  void* do_allocate(size_t bytes, size_t alignment) override;
513
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;
514
 
515
  bool do_is_equal(const memory_resource& other) const noexcept override;
516
  };
517
+ }
518
  ```
519
 
520
  #### `pool_options` data members <a id="mem.res.pool.options">[[mem.res.pool.options]]</a>
521
 
522
  The members of `pool_options` comprise a set of constructor options for
 
526
  ``` cpp
527
  size_t max_blocks_per_chunk;
528
  ```
529
 
530
  The maximum number of blocks that will be allocated at once from the
531
+ upstream memory resource [[mem.res.monotonic.buffer]] to replenish a
532
  pool. If the value of `max_blocks_per_chunk` is zero or is greater than
533
  an *implementation-defined* limit, that limit is used instead. The
534
  implementation may choose to use a smaller value than is specified in
535
  this field and may use different values for different pools.
536
 
 
544
  If `largest_required_pool_block` is zero or is greater than an
545
  *implementation-defined* limit, that limit is used instead. The
546
  implementation may choose a pass-through threshold larger than specified
547
  in this field.
548
 
549
+ #### Constructors and destructors <a id="mem.res.pool.ctor">[[mem.res.pool.ctor]]</a>
550
 
551
  ``` cpp
552
  synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
553
  unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
554
  ```
555
 
556
+ *Preconditions:* `upstream` is the address of a valid memory resource.
557
 
558
  *Effects:* Constructs a pool resource object that will obtain memory
559
  from `upstream` whenever the pool resource is unable to satisfy a memory
560
  request from its own internal data structures. The resulting object will
561
  hold a copy of `upstream`, but will not own the resource to which
 
577
  virtual ~unsynchronized_pool_resource();
578
  ```
579
 
580
  *Effects:* Calls `release()`.
581
 
582
+ #### Members <a id="mem.res.pool.mem">[[mem.res.pool.mem]]</a>
583
 
584
  ``` cpp
585
  void release();
586
  ```
587
 
 
611
 
612
  ``` cpp
613
  void* do_allocate(size_t bytes, size_t alignment) override;
614
  ```
615
 
616
+ *Returns:* A pointer to allocated
617
+ storage [[basic.stc.dynamic.allocation]] with a size of at least
618
+ `bytes`. The size and alignment of the allocated memory shall meet the
619
+ requirements for a class derived from `memory_resource`
620
+ [[mem.res.class]].
621
 
622
  *Effects:* If the pool selected for a block of size `bytes` is unable to
623
  satisfy the memory request from its own internal data structures, it
624
  will call `upstream_resource()->allocate()` to obtain more memory. If
625
  `bytes` is larger than that which the largest pool can handle, then
 
636
  `upstream_resource()->deallocate()`.
637
 
638
  *Throws:* Nothing.
639
 
640
  ``` cpp
641
+ bool do_is_equal(const memory_resource& other) const noexcept override;
 
642
  ```
643
 
644
+ *Returns:* `this == &other`.
 
 
 
 
 
 
 
 
 
645
 
646
  ### Class `monotonic_buffer_resource` <a id="mem.res.monotonic.buffer">[[mem.res.monotonic.buffer]]</a>
647
 
648
  A `monotonic_buffer_resource` is a special-purpose memory resource
649
  intended for very fast memory allocations in situations where memory is
 
663
  with one another.
664
  - It frees the allocated memory on destruction, even if `deallocate` has
665
  not been called for some of the allocated blocks.
666
 
667
  ``` cpp
668
+ namespace std::pmr {
669
  class monotonic_buffer_resource : public memory_resource {
670
  memory_resource* upstream_rsrc; // exposition only
671
  void* current_buffer; // exposition only
672
  size_t next_buffer_size; // exposition only
673
 
674
  public:
675
  explicit monotonic_buffer_resource(memory_resource* upstream);
676
  monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
677
+ monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
 
678
 
679
  monotonic_buffer_resource()
680
  : monotonic_buffer_resource(get_default_resource()) {}
681
  explicit monotonic_buffer_resource(size_t initial_size)
682
  : monotonic_buffer_resource(initial_size, get_default_resource()) {}
 
685
 
686
  monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
687
 
688
  virtual ~monotonic_buffer_resource();
689
 
690
+ monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
 
691
 
692
  void release();
693
  memory_resource* upstream_resource() const;
694
 
695
  protected:
696
  void* do_allocate(size_t bytes, size_t alignment) override;
697
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;
698
 
699
  bool do_is_equal(const memory_resource& other) const noexcept override;
700
  };
701
+ }
702
  ```
703
 
704
+ #### Constructors and destructor <a id="mem.res.monotonic.buffer.ctor">[[mem.res.monotonic.buffer.ctor]]</a>
705
 
706
  ``` cpp
707
  explicit monotonic_buffer_resource(memory_resource* upstream);
708
  monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
709
  ```
710
 
711
+ *Preconditions:* `upstream` is the address of a valid memory resource.
712
+ `initial_size`, if specified, is greater than zero.
713
 
714
  *Effects:* Sets `upstream_rsrc` to `upstream` and `current_buffer` to
715
  `nullptr`. If `initial_size` is specified, sets `next_buffer_size` to at
716
  least `initial_size`; otherwise sets `next_buffer_size` to an
717
  *implementation-defined* size.
718
 
719
  ``` cpp
720
  monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
721
  ```
722
 
723
+ *Preconditions:* `upstream` is the address of a valid memory resource.
724
+ `buffer_size` is no larger than the number of bytes in `buffer`.
725
 
726
  *Effects:* Sets `upstream_rsrc` to `upstream`, `current_buffer` to
727
  `buffer`, and `next_buffer_size` to `buffer_size` (but not less than 1),
728
  then increases `next_buffer_size` by an *implementation-defined* growth
729
  factor (which need not be integral).
 
732
  ~monotonic_buffer_resource();
733
  ```
734
 
735
  *Effects:* Calls `release()`.
736
 
737
+ #### Members <a id="mem.res.monotonic.buffer.mem">[[mem.res.monotonic.buffer.mem]]</a>
738
 
739
  ``` cpp
740
  void release();
741
  ```
742
 
 
755
 
756
  ``` cpp
757
  void* do_allocate(size_t bytes, size_t alignment) override;
758
  ```
759
 
760
+ *Returns:* A pointer to allocated
761
+ storage [[basic.stc.dynamic.allocation]] with a size of at least
762
+ `bytes`. The size and alignment of the allocated memory shall meet the
763
+ requirements for a class derived from `memory_resource`
764
+ [[mem.res.class]].
765
 
766
  *Effects:* If the unused space in `current_buffer` can fit a block with
767
  the specified `bytes` and `alignment`, then allocate the return block
768
  from `current_buffer`; otherwise set `current_buffer` to
769
  `upstream_rsrc->allocate(n, m)`, where `n` is not less than
 
787
 
788
  ``` cpp
789
  bool do_is_equal(const memory_resource& other) const noexcept override;
790
  ```
791
 
792
+ *Returns:* `this == &other`.
 
793