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
n
T
objects in the area pointed to byp
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:
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)
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 T
objects in the area pointed to byp
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.
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 — Allocator
requirementsExpression Return type Assertion/note
pre-/post-conditionDefault …
a.deallocate(p,n)
(not used) Pre: p
shall be a value returned by an earlier
call toallocate
which has not been invalidated by
an intervening call todeallocate
.n
shall
match the value passed toallocate
to obtain this
memory.Alln 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]…