deallocate function needs better specificationSection: 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
nTobjects in the area pointed to bypshall be destroyed prior to this call.nshall match the value passed to allocate to obtain this memory. Does not throw exceptions. [Note:pshall not be singular. — end note]
This wording is confusing in regard to the following points:
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:
ptrshall 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)oroperator new(std::size_t,const std::nothrow_t&)which has not been invalidated by an intervening call tooperator delete(void*).
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 Tobjects in the area pointed to bypshall 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.
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.
Change Table 28 ("Allocator requirements") as indicated:
Table 28 — AllocatorrequirementsExpression Return type Assertion/note
pre-/post-conditionDefault …a.deallocate(p,n)(not used) Pre: pshall be a value returned by an earlier
call toallocatewhich has not been invalidated by
an intervening call todeallocate.nshall
match the value passed toallocateto obtain this
memory.Alln Tobjects in the area pointed to by
pshall 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:pshall not
be singular. — end note]…