Have you thought about how std::allocator<>::allocate_at_least
might usefully discover whether the ::op new (it is obliged by the
Standard to use) is the one in libstdc++, and will supply extra
details about memory allocated, not one the user has supplied and
the linker has substituted in its place? Ideally it would all be
decided at link time, and not conditionally in every call, but
linker magic is fragile even without LTO. And users can call ::op
new directly, with no #include to declare it.
Maybe pass an extra argument to ::op new that the user's version
won't notice, and that ours may discover is present by looking at
the stack frame? The extra argument might be a pointer to a place
to scribble extra details. (A hint argument might be placed there,
besides.) But stack frame conventions vary too.
-N
On 3/8/26 7:01 AM, Jonathan Wakely wrote:
On Sat, 7 Mar 2026, 12:38 Nathan Myers, <[email protected]
+ * @return Memory of suitable size and alignment for @a n or
more
+ * contiguous objects of type @c value_type .
Please use markdown for new doxygen comments instead of doxygen's @c or
html like <tt>. In general only back ticks are needed, and they're more
readable then the alternatives.
Good.
+ *
+ * Returns <tt> a.allocate_at_least(n) </tt> if that expression
+ * is well-formed, else <tt> { a.allocate(n), n } </tt>. When an
+ * allocator is obliged to reserve more space than required for
+ * the cited @c n objects, it may deliver the extra space to the
+ * caller.
+ */
+ [[nodiscard]] static constexpr auto
+ allocate_at_least(_Alloc& __a, size_type __n)
+ -> allocation_result<pointer, size_type>
+ {
+ static_assert(requires { sizeof(value_type); },
+ "allocated object type must be complete");
Does using a requires-expression make a difference here, rather than
just sizeof directly?
Just that it writes out the error message attached.
+ if constexpr (requires { __a.allocate_at_least(__n); })
+ return __a.allocate_at_least(__n);
+ else
+ return { __a.allocate(__n), __n };
+ }
+#endif
+
/**
* @brief Deallocate memory.
* @param __a An allocator.
@@ -635,6 +662,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
}
+#ifdef __glibcxx_allocate_at_least // C++23
+ /**
+ * @brief Allocate memory, generously.
+ * @param __a An allocator.
+ * @param __n The minimum number of objects to allocate
space for.
+ * @return Memory of suitable size and alignment for @a n or
more
+ * contiguous objects of type @c value_type .
+ *
+ * Returns <tt> a.allocate_at_least(n) </tt>.
+ */
+ [[nodiscard]] static constexpr auto
+ allocate_at_least(allocator_type __a, size_type __n)
+ -> allocation_result<pointer, size_type>
+ {
+ static_assert(requires { sizeof(value_type); },
+ "allocated object type must be complete");
I think this static_assert is redundant, because
std::allocator::allocate_at_least calls std::allocator::allocate which
checks the same condition.
But, does it? Maybe it should. I have it here only because the Standard
says "Mandates:", which I have (mistakenly?) interpreted as requiring
a call-site diagnostic.
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -61,6 +61,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @{
*/
+#ifdef __glibcxx_allocate_at_least // C++23
+ template <typename _Pointer, typename _Size = size_t>
+ struct allocation_result
Defining this type here means it won't be declared in bits/
alloc_traits.h for freestanding, because of:
# if _GLIBCXX_HOSTED
# include <bits/allocator.h>
# endif
I think it would be better in bits/memoryfwd.h
Good catch.
+ {
+ _Pointer ptr;
+ _Size count;
+ };
+#endif
+
... > +#ifdef __glibcxx_allocate_at_least // C++23
+ [[nodiscard]] constexpr allocation_result<_Tp*, size_t>
+ allocate_at_least(size_t __n)
+ { return { this->allocate(__n), __n }; }
+#endif
See, no static_assert here.