根据cppref:
std::allocator<T>::allocate_at_least
分配
字节的未初始化存储,其中count * sizeof(T)
是一个不小于count
的未指定整数值,通过调用n
(额外的::operator new
论点可能是 提供),但未指定何时以及如何调用此函数。std::align_val_t
然后,这个函数在存储中创建一个
类型的数组 并开始其生命周期,但不开始其任何生命周期 元素。T[count]
std::allocator<T>::allocate
可以做同样的事情。
为什么在 C++23 中我们需要
std::allocator<T>::allocate_at_least
?
allocate
可能会分配比请求更多的元素,但它无法将实际分配的大小返回给调用者。
这就是
allocate_at_least
的目的,它的实现可能和allocate
一样,也可能分配完全相同数量的元素,不同的是它能够返回分配给调用者的元素数量,这意味着如有必要,调用者可以使用这些额外的元素。
allocate_at_least
与 allocate
不一样。比较(allocate
):
Allocates
bytes of uninitialized storage...n * sizeof(T)
与(
allocate_at_least
):
Allocates
bytes of uninitialized storage,其中count * sizeof(T)
是一个未指定的整数值,不小于count
...n
此外,
allocate
返回:
指向
类型的对象数组的第一个元素的指针n
...T
当
allocate_at_least
返回时:
,其中std::allocation_result<T*>{p, count}
指向p
count
类型的对象的数组的第一个元素...T
调用者因此获得有关实际分配大小的信息。
动机可见P0401R6;部分动机:
考虑向向量添加元素的代码:
std::vector<int> v = {1, 2, 3}; // Expected: v.capacity() == 3 // Add an additional element, triggering a reallocation. v.push_back(4);
许多分配器只分配固定大小的内存块,四舍五入请求。我们的底层堆分配器在构造 v 时收到了一个 12 字节 (
) 的请求。对于几个实现,这个请求变成了一个 16 字节的区域。3 * sizeof(int)
这来自cppref的笔记:
allocate_at_least 主要是为连续的容器提供的,例如std::vector 和 std::basic_string,以便 通过使它们的容量尽可能匹配实际分配的大小来减少重新分配。
“未指定时间和方式” 措辞使得组合或 优化标准库进行的堆外分配 容器,即使这种优化对于直接 调用 ::operator new。比如这个是libc++实现的
在调用 allocate_at_least 之后和构造元素之前, T* 的指针算术在分配的数组中定义明确, 但如果访问元素,则行为未定义。