[PATCH] libstdc++: Add allocate_at_least (P0401) [PR118030]

Nathan Myers ncm@cantrip.org
Tue Mar 10 18:22:08 GMT 2026


On 3/10/26 1:43 PM, Jonathan Wakely wrote:
> On Tue, 10 Mar 2026 at 17:35, Nathan Myers <ncm@cantrip.org> wrote:
>>
>> First, there is no Standard expectation that any of
>>
>>     ::operator delete(std::malloc(n))
>>     std::free(::operator new(n))
>>     ::operator delete(std::allocator<char>::allocate(n))
>>     [etc.]
>>
>> works, although some users may have written programs that
>> rely on it for their target platform.
> 
> Yes, obviously. Nobody is suggesting that should work. Valgrind and
> Asan will both diagnose such bugs.
> 
>> However it is obviously necessary (given "using A =
>> std::allocator<T>;") for
>>
>>     A::deallocate(A::allocate(n)), n)
>>     A::deallocate(A::allocate_at_least(n), n)
>>
>> both to work, and practical reasons why mixing allocations of
>> T and deallocations via char should, too.
>>
>>> Yes, so both allocate and allocate_at_least would need to reserve
>>> extra memory in order to store a cookie before the return value,
>>> which would say which function was used to allocate the memory.
>>> Then deallocate would inspect the cookie to decide how to do the
>>> deallocation. This adds overhead and uses extra memory, and can't
>>> be done in the templated functions in the allocator class template,
>>> because otherwise it becomes part of the ABI forever.
>>   >
>>   > And the extra space and time overhead would affect all uses of
>>   > std::allocator, not only the ones that are opting in to the
>>   > new API by calling allocate_at_least.
>>
>> There is no need for a cookie. Trivially, implementing
>>
>>     A::allocate(n) { return A::allocate_at_least(n).ptr; }
>>
>> is allowed.
> 
> That's what I've been saying all along, you're the one who raised the
> topic of storing a cookie (or other side channel) for allocate(n) to
> communicate with deallocate(p, n).

Every allocator/deallocator necessarily stores side-channel data.
Using malloc underneath, we skate by on what it does. The point
is that we don't need to use malloc underneath: we can do better,
and are not constrained by compatibility with malloc's choices.

>>> And what would the new logic for allocate_at_least even do? Are we
>>> going to reimplement an entire malloc, just to be able to return a few
>>> more bytes? Using mmap doesn't give you a high performance allocator,
>>> you still need to implement a malloc-like thing on top of raw mmap.
>>> Using jemalloc isn't an option unless we bundle [it].
>>>
>>> I'm not persuaded that this is worth doing.
>>>
>>> P0901 would have meant the additional logic happens in the right
>>> place, in an operator new which is replaceable. I don't think doing it
>>> in std::allocator is a good idea.
>>
>> The gains available from using a better-designed allocator,
>> whether one coded from scratch or by importation, are very
>> substantial, with or without substantive allocate_at_least
>> support, although such gains would vary radically from one
>> program to another. I saw three orders of magnitude difference
>> in performance between different allocators, during the Unix
>> wars. (SGI was slowest, DEC fastest, but still 10x slower
>> than mine and with 1.5x total footprint; that last mattered
>> a lot, then.)
> 
> Why would we want to do that in libstdc++ instead of doing it in
> glibc, so it benefits all out customers?

It doesn't matter where it is done, provided that its extra
features, not limited to support for a useful allocate_at_least,
are exposed so libstdc++ can use them. But we don't control
glibc. Allowing users to plug in a third-party allocator and
not wait for glibc to implement whatever the third-party
allocator does would be a direct benefit for users of libstdc++.

>> The amount of extra storage deliverable to allocate_at_least()
>> with a bespoke design could be (often) much larger than what we
>> get from rounding up to an alignment boundary. (Arguably, the
>> only case where that last is worth doing is when sizeof(T) is 1.)
> 
> The goal is P0401 is not to maximize the amount of additional storage
> it makes available, just to let the application use the additional
> storage that the allocator naturally makes available without needing
> to do any extra work.
> 
> (and rounding up to max_align_t seems worthwhile for int-sized types,
> not just for bytes).

The amount of storage wasted by the allocator underlying
std::allocator is often much larger than can be reclaimed just
by rounding up to an alignment boundary. Exposing more of such
storage is not a reason to make a new allocation engine, but it
is a benefit that would be cheap for a new allocation engine to
provide.

>> Whether those gains are worth the investment is a business
>> decision, which depends heavily on how much work is invested.
>> Providing a way (whether proprietary or eventually Standard) to
>> plug in a third-party allocator could be much less work than
>> implementing a new allocator engine from scratch, and then
>> different third-party libraries could be tried for different
>> programs.
> 
> Then we should consider a design more like P0901, not invent new side
> channels in the existing API.
> 
> I still don't think we should make any such changes to std::allocator
> or operator new at this time.

Certainly not for Gcc 16.



More information about the Libstdc++ mailing list