3

std::string::reserve()没有分配我作为参数传递的确切空间量。例如,如果我尝试为 100 个字符保留空间,它会为 111 个字符保留空间。如果我通过 200,它会为 207 保留。655 为 650,1007 为 1000。

这背后的原因是什么?

程序代码:

std::string mystr;
std::cout << "After creation   :" << mystr.capacity() << std::endl;
mystr.reserve(1000);
std::cout << "After reserve()  :" << mystr.capacity() << std::endl;
mystr = "asd";
std::cout << "After assignment :" << mystr.capacity() << std::endl;
mystr.clear();
std::cout << "After clear()    :" << mystr.capacity() << std::endl;

代码输出:

After creation   :15
After reserve()  :1007
After assignment :1007
After clear()    :1007

(IDE:Visual Studio 2012)

4

3 回答 3

7

标准允许

C++ 标准允许实现保留比请求更多的内存。在标准(N3690,§21.4.4)中,它声明

void reserve(size_type res_arg=0);

成员函数reserve()是一个指令,它通知basic_string对象计划的大小更改,以便它可以相应地管理存储分配。

效果:之后reserve()capacity()大于或等于 的参数reserve。[注意:使用小于reserve()的参数调用实际上是一个非绑定收缩请求。调用实际上是一个不具约束力的缩小以适应请求。——尾注]res_argcapacity()res_arg <= size()

原因:在 16 字节边界上对齐

似乎保留大小始终是一个数字,它是 16 的倍数减去一个用于空终止的字符。在 x86 机器上,堆上保留的内存总是自动 16 字节对齐。因此,对于内存分配,四舍五入到 16 的下一个最大倍数是没有成本的。

Microsoft 文档malloc()说明:

返回值所指向的存储空间保证被适当对齐以存储任何类型的对象。

SIMD 类型的对象必须以16 字节对齐才能最佳工作。这些是适合 x86 机器的 128 位寄存器的 4 个浮点数或 2 个双精度数(或其他)的打包类型。如果数据没有正确对齐,那么加载和存储到这些内存位置可能会导致性能严重下降甚至崩溃。这就是为什么malloc()这样做。因此得出 16 字节对齐的结论。大多数内存分配(包括operator new)最终调用malloc(). 不分配 16 字节的倍数只会浪费内存,否则无论如何都不会使用。

于 2013-07-08T14:37:10.197 回答
5

该标准不要求它准确地保留您指定的内容,至少只保留您指定的内容:

21.4.4 basic_string容量[string.capacity]

12/效果:reserve()之后,capacity()大于或等于reserve的参数。[ 注意:使用小于 capacity() 的 res_arg 参数调用 reserve() 实际上是一个非绑定收缩请求。res_arg <= size() 的调用实际上是一个非绑定的缩小以适应请求。——尾注]

于 2013-07-08T14:34:33.263 回答
0

我必须查看源代码才能 100% 确定,但看起来底层代码正在保留您请求的数量并将其填充到下一个 16 字节边界(为空终止保留 1)这只是基于的理论行为。

于 2013-07-08T14:38:40.230 回答