为什么`std :: string :: reserve()`没有保留我指定的确切空间量?

时间:2013-07-08 14:30:08

标签: c++ memory-management stl stdstring

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)

3 个答案:

答案 0 :(得分:7)

标准允许

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

void reserve(size_type res_arg=0);
     

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

     

效果:reserve()之后,capacity()大于或等于reserve的参数。 [注意:使用reserve()参数小于res_arg调用capacity()实际上是非绑定收缩请求。使用res_arg <= size()的呼叫实际上是一种非绑定的缩小到适合请求。 - 结束记录]

原因:对齐16字节边界

似乎保留的大小始终是16的倍数减去空终止的一个字符的数字。堆上保留的内存始终在x86计算机上自动进行16字节对齐。因此,对于内存分配,没有成本可以累计到16的下一个最大倍数。

Microsoft documentation for malloc()表示:

  

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

Objects of SIMD type必须16-byte aligned才能发挥最佳效果。这些是4个浮点数或2个双打(或其他)的打包类型,适合x86机器的128位寄存器。如果数据未正确对齐,则加载和存储到这些存储器位置会导致性能损失甚至崩溃。这就是malloc()这样做的原因。因此,16字节对齐的结论。大多数内存分配(包括operator new)最终都会调用malloc()。不分配16个字节的倍数只会浪费内存,否则无论如何都不会使用。

答案 1 :(得分:5)

标准不要求它保留完全您指定的内容,至少只保留您指定的内容:

21.4.4 basic_string capacity [string.capacity]

  

12 /效果:在reserve()之后,capacity()大于或等于   储备论证。 [注意:使用res_arg参数调用reserve()   小于capacity()实际上是一个非绑定收缩请求。一个电话   res_arg&lt; = size()实际上是一种非约束性的缩小   请求。 - 后注]

答案 2 :(得分:0)

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