Why is allocator<void> deprecated?

675 views
Skip to first unread message

Andrey Semashev

unread,
Jan 2, 2018, 5:30:30 PM1/2/18
to std-dis...@isocpp.org
Hi,

I'm surprized to discover that C++17 deprecated std::allocator<void>
specialization. I can understand the will to move to allocator_traits
for accessing types and functions that were previously members of
std::allocator, but I don't understand why the specialization is
deprecated. In my view this specialization is the *only* one that makes
sense to specify in most containers' template argument (because the
container's node is not known to the user and the value type is useless
since the allocator will be rebound to the node type anyway).

So my questions are why is it deprecated and what is the recommended
replacement in the user's code, when one just needs to communicate the
allocator type regardless of the allocated type.

Andrey Semashev

unread,
Jan 5, 2018, 8:44:55 AM1/5/18
to std-dis...@isocpp.org
Ping? Does anyone know?

I'm surprised by the lack of interest because allocator<void> seems like
a useful concept to me. I'm using it rather often in my code.

Nicol Bolas

unread,
Jan 5, 2018, 11:10:40 AM1/5/18
to ISO C++ Standard - Discussion
According to P0174:

std::allocator<void> is defined so that various template rebinding tricks could work in the original C++98 library, but it is not an actual allocator, as it lacks both allocate and deallocate member functions, which cannot be synthesized by default from allocator_traits. That need went away with C++11 and the void_pointer and const_void_pointer type aliases in allocator_traits. However, we continue to specify it in order to avoid breaking old code that has not yet been upgraded to support generic allocators, per C++11.

Essentially, I interpret this as them saying that the Allocator concept allocates objects, not memory. As such, `std::allocator<void>` is a nonsense type; `void` is an incomplete type and therefore cannot be allocated.

By deprecating the specialization, it makes it clear that `void` allocators are not supposed to be used. You may view this specialization as "the *only* one that makes sense", but that's not how it is meant to be used. The fact that a different allocator specialization may be used is essentially an implementation detail.

Also, aren't node-based containers still required to use `allocator<value_type>` to construct and destroy the `value_type` contents of their nodes? If so, then passing an `allocator<T>` still makes plenty of sense.

Andrey Semashev

unread,
Jan 5, 2018, 12:01:01 PM1/5/18
to std-dis...@isocpp.org
On 01/05/18 19:10, Nicol Bolas wrote:
>
> According to P0174
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r0#2.4>:
>
> > std::allocator<void> is defined so that various template rebinding
> tricks could work in the original C++98 library, but it is not an actual
> allocator, as it lacks both allocate and deallocate member functions,
> which cannot be synthesized by default from allocator_traits. That need
> went away with C++11 and the void_pointer and const_void_pointer type
> aliases in allocator_traits. However, we continue to specify it in order
> to avoid breaking old code that has not yet been upgraded to support
> generic allocators, per C++11.
>
> Essentially, I interpret this as them saying that the Allocator concept
> allocates/objects/, not memory. As such, `std::allocator<void>` is a
> nonsense type; `void` is an incomplete type and therefore cannot be
> allocated.

Allocators do allocate memory separately from creating objects. But it
is true that `std::allocator<void>` was not meant to be used to allocate
memory or create objects; my intent is not to make that possible.
Instead, `std::allocator<void>` communicates the "kind" of the allocator
to use for allocating whatever objects the container needs to.

I would never expect the container to use `std::allocator<void>` (or
`std::allocator<T>`) directly; instead I would expect the container to
always rebind the allocator as it sees fit.

> By deprecating the specialization, it makes it clear that `void`
> allocators are not supposed to be used. You may view this specialization
> as "the *only* one that makes sense", but that's not how it is meant to
> be used. The fact that a different allocator specialization may be used
> is essentially an implementation detail.
>
> Also, aren't node-based containers still required to use
> `allocator<value_type>` to//construct and destroy the `value_type`
> contents of their nodes? If so, then passing an `allocator<T>` still
> makes plenty of sense.

First, even if they must use `allocator<value_type>` to create values,
they also must allocate and create nodes using `allocator<node_type>`,
so they must rebind the allocator anyway. I don't think that requiring
to use `allocator<value_type>` is reasonable though as it offers no
advantage.

Second, whatever allocator specializations the container use internally
is rightfully an implementation detail. That is why requiring
`allocator<T>` in the container's template arguments makes no sense and
`allocator<void>` makes more sense as it avoids duplication. It makes
yet more sense for user's types that allocate multiple objects of
different types with no single `value_type`.

Lingxi Li

unread,
May 8, 2018, 11:15:37 PM5/8/18
to ISO C++ Standard - Discussion
Ran into exactly the same question and was directed here from StackOverflow.
Alas, neither gcc 8 nor clang 6 works for `std::list<int, std::allocator<void>>`.

Lingxi Li

unread,
May 9, 2018, 12:18:20 AM5/9/18
to ISO C++ Standard - Discussion


On Saturday, January 6, 2018 at 1:01:01 AM UTC+8, Andrey Semashev wrote:
Reply all
Reply to author
Forward
0 new messages