ISO/ IEC JTC1/SC22/WG21 N2339

Detlef Vollmann <dv@vollmann.ch>
N2339=07-0199
2007-07-16

[This is the paper we discussed in Toronto just for the records.]

Response to N2257=07-0117 "Removing unused allocator functions"

Summary
N2257 proposes to remove functions that are claimed to be unused from
the allocator requirements.
Those functions are not unused, so removing them will break existing code.
And if those functions are removed, other changes are required as well.


Introduction
In Oxford, suddenly a motion came up to remove functions from the
allocator requirements.  This took my by surprise and immediately
alerted me as I had written allocators with such functions which were
not necessaryly trivial.
So this paper provides some background on my concerns about the removal.


"Unused"
N2257 claims that "Nothing in the standard requires containers to call
allocators' construct, destroy, or address member functions".
That is only true for implementations that use the leeway given
in 20.1.2p4.  I might be wrong, but I think otherwise there exists
no requirement that allocator::pointer is convertible to 'void*',
which would be required for using placement new directly.
See also issue 401 on that.
One way to get from an allocator::pointer p to a void* might be to
use '&(*p)'.  But as issue 634 points out, this isn't required to work.
So, a conformant implementation that doesn't make use of 20.1.2p4
must use either allocator::address() or allocator::construct(),
and quality implementations currently do so.
The same goes for allocator::destroy().
Allocator::address() is not required for container implementations,
but for a user of the container there's no other way to obtain
an allocator::pointer from an object in the container, should
the need arise.


Allocator::pointer
Apart from 20.1.2p4, the current standard doesn't require
allocator::pointer to be T*.
So the status of 20.1.2p4 is the real question.  If it is an
absolute requirement that allocator::pointer is T*, then the
functions allocator::construct(), allocator::destroy() and
allocator::address() are indeed not required and can go away.
But then this should be clearly stated.
If allocator::pointer is allowed to be something different
than T*, those functions must be there.
But in this case, allocator::pointer is completely underspecified
and N2257 even proposes to remove the only specification that is
there (existance of a unary * operator).


Breakage
Many library implementation currently do the "right thing", i.e.
call allocator::construct().  With the proposed change in N2257
they would have to call placement new directly and circumvent any
existing allocator::construct() function.  If there currently exists
a non-trivial allocator::construct() function, things will break
silently when changing to a new library implementation.


Conclusion
The proposal in N2257 to remove some allocator functions is really
an attempt to require allocator::pointer to be T*.
But several allocator implementations exist that use successfully
other pointer types (I myself wrote some shared memory allocators).
So the removal would not only render existing code unusable but
also would make attempts to implement such allocators very hard.
One way to get rid of the unwanted functions would be to add a
requirement to allocator::pointer to provide an (implicit)
conversion to void*, but not calling construct() and destroy()
will still break existing code.