Providing size feedback in the Allocator interface

Published Proposal,

This version:
ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++


Utilize size feedback from Allocator to reduce spurious reallocations

1. Introduction

This is a library paper to describe how size feedback can be used with allocators:

2. Motivation

Consider code adding elements to vector:

std::vector<int> v = {1, 2, 3};
// Expected: v.capacity() == 3

// Add an additional element, triggering a reallocation.

Many allocators only allocate in fixed-sized chunks of memory, rounding up requests. Our underlying heap allocator received a request for 12 bytes (3 * sizeof(int)) while constructing v. For several implementations, this request is turned into a 16 byte region.

2.1. Why not realloc

realloc poses several problems problems:

For fixed-size allocators it makes more sense, and is much simpler for containers to adapt to, if the allocator is able to over-allocate on the initial request and inform the caller how much memory was made available.

2.2. Why not ask the allocator for the size

We could also explore APIs that answer the question: "If I ask for N bytes, how many do I actually get?" [jemalloc] calls this nallocx.

See also [P0901R5]'s discussion "nallocx: not as awesome as it looks."

3. Proposal

Wording relative to [N4800].

We propose a free function to return the allocation size simultaneously with an allocation.

Amend [allocator.requirements]:

template<typename T = void>
struct sized_ptr_t {
  T *ptr;
  size_t n;

template<typename T, typename Allocator = std::allocator<T>>
sized_ptr_t<T> allocate_at_least(Allocator& a, size_t n);

Table 34 - Cpp17Allocator Requirements

a.deallocate(p,n) (not used) Requires: p shall be a value returned by an earlier call to allocate or allocate_at_least that has not been invalidated by an intervening call to deallocate. If this memory was obtained by a call to allocate, n shall match the value passed to allocate to obtain this memory. Otherwise, n shall satisfy capacity >= n >= requested where [p, capacity] = allocate_at_least(requested) was used to obtain this memory.

Throws: Nothing.

4. Design Considerations

4.1. allocate selection

There are multiple approaches here:

4.2. deallocate changes

We now require flexibility on the size we pass to deallocate. For container types using this allocator interface, they are faced with the choice of storing both the original size request as well as the provided size (requiring additional auxillary storage), or being unable to reproduce one during the call to deallocate.

As the true size is expected to be useful for the capacity of a string or vector instance, the returned size is available without additional storage requirements. The original (requested) size is unavailable, so we relax the deallocate size parameter requirements for these allocations.

4.3. Interaction with polymorphic_allocator

std::pmr::memory_resource is implemented using virtual functions. Adding new methods, such as the proposed allocate API would require taking an ABI break.

5. Revision History

5.1. R1 → R2

Applied LEWG feedback from [Cologne].

Poll: We want a feature like this.
2 9 2 0 0
Poll: Name choice
5 allocate_with_size
4 overallocate
2 allocate_with_oversubscribe
6 allocate_oversize
14 allocate_at_least

Poll: Prefer a struct rather than a requirement of structured bindings.

2 8 0 2 1


Informative References

Cologne Meeting Minutes. 2019-07-17. URL: http://wiki.edg.com/bin/view/Wg21cologne2019/P0401
jemalloc(3) - Linux man page. URL: http://jemalloc.net/jemalloc.3.html
Ariane van der Steldt. inplace realloc. 7 December 2012. URL: https://wg21.link/n3495
Working Draft, Standard for Programming Language C++. 2019-01-21. URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4800.pdf
realloc for C++. 2019-01-18. URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0894r1.md
Size feedback in operator new. 2019-10-03. URL: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0901r5.html