This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2384. Allocator's `deallocate` function needs better specification

Section: 16.4.4.6 [allocator.requirements] Status: C++17 Submitter: Daniel Krügler Opened: 2014-05-19 Last modified: 2017-07-30

Priority: 3

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with C++17 status.

Discussion:

According to Table 28, 16.4.4.6 [allocator.requirements], an `Allocator`'s `deallocate` function is specified as follows:

> All `n` `T` objects in the area pointed to by `p` shall be destroyed prior to this call. `n` shall match the value passed to allocate to obtain this memory. Does not throw exceptions. [Note: `p` shall not be singular. — end note]

This wording is confusing in regard to the following points:

1. This specification does not make clear that the result of an `allocate` call can only be returned once to the `deallocate` function. This is much clearer expressed for `operator delete` (17.6.3.2 [new.delete.single] p12, emphasis mine):

   > Requires: `ptr` shall be a null pointer or its value shall be a value returned by an earlier call to the (possibly replaced) `operator new(std::size_t)` or `operator new(std::size_t,const std::nothrow_t&)` which has not been invalidated by an intervening call to `operator delete(void*)`.

2. The intended meaning of that wording was to say that `deallocate` shall accept every result value that had been returned by a corresponding call to `allocate`, this includes also a possible result of a null pointer value, which is possible ("[Note: If `n == 0`, the return value is unspecified. — end note]"). Unfortunately the `deallocate` function uses a non-normative note ("`p` shall not be singular.") which refers to the fuzzy term `singular`, that is one of the most unclear and misunderstood terms of the library, as pointed out in 1213. The occurrence of this term has lead to the possible understanding, that this function would never allow null pointer values. Albeit for allocators the intention had not been to require the support in general that a null pointer value can be provided to `deallocate` (as it is allowed for `std::free` and `operator delete`), the mental model was that every returned value of `allocate` shall be an acceptable argument type of the corresponding `deallocate` function.

This issue is not intending to enforce a specific meaning of singular iterator values, but the assertion is that this note does more harm than good. In addition to wording from `operator delete` there is no longer any need to obfuscate the normative wording.

[2014-05-24 Alisdair comments]

Now that I am reading it very precisely, there is another mis-stated assumption as a precondition for `deallocate`:

> All `n T` objects in the area pointed to by `p` shall be destroyed prior to this call.

This makes a poor assumption that every possible object in the allocated buffer was indeed constructed, but this is often not the case, e.g., a `vector` that is not filled to capacity. We should require calling the destructor for only those objects actually constructed in the buffer, which may be fewer than `n`, or even 0.

I wonder if we really require all objects to be destroyed before calling `deallocate` though. Are we really so concerned about leaking objects that might not manage resources? Should this not be the proper concern of the library managing the objects and memory?

[2014-06-05 Daniel responds and improves wording]

I fully agree with the last comment and I think that this requirement should be removed. We have no such requirements for comparable functions such as `operator delete` or `return_temporary_buffer()`, and this wording seems to be a wording rudiment that exists since C++98.

[2015-05, Lenexa]

Marshall: What do people think about this?
PJP: Sure.
Wakely: Love it.
Marshall: Ready?
Everyone agrees.

Proposed resolution:

This wording is relative to N3936.

1. Change Table 28 ("`Allocator` requirements") as indicated:

   > Table 28 — `Allocator` requirements
   > Expression | Return type | Assertion/note pre-/post-condition | Default
   > --- | --- | --- | ---
   > `…`
   > `a.deallocate(p,n)` | (not used) | Pre: `p` shall be a value returned by an earlier call to `allocate` which has not been invalidated by an intervening call to `deallocate`. `n` shall match the value passed to `allocate` to obtain this memory. All `n T` objects in the area pointed to by `p` shall be destroyed prior to this call. Throws: Nothing.`n` shall match the value passed to allocate to obtain this memory. Does not throw exceptions. [Note: `p` shall not be singular. — end note] |
   > `…`