std::string::reserve() doesn't allocate the exact amount of space I pass as argument. For example, if I try to reserve space for 100 characters, it reserves for 111 characters. If I pass 200, it reserves for 207. 655 for 650, 1007 for 1000.

What is the reason behind this?

Program code:

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;

Code output:

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

(IDE: Visual Studio 2012)

有帮助吗?

解决方案

The standard allows it

The C++ standard allows the implementation to reserve more memory than requested. In the standard (N3690, §21.4.4) it states

void reserve(size_type res_arg=0);

The member function reserve() is a directive that informs a basic_string object of a planned change in size, so that it can manage the storage allocation accordingly.

Effects: After reserve(), capacity() is greater or equal to the argument of reserve. [ Note: Calling reserve() with a res_arg argument less than capacity() is in effect a non-binding shrink request. A call with res_arg <= size() is in effect a non-binding shrink-to-fit request. — end note ]

The reason: Alignment on 16-byte boundaries

It seems that the reserved size is always a number that is a multiple of 16 minus one character for null termination. Memory reserved on the heap is always automatically 16-byte aligned on a x86 machine. Hence there is no cost in rounding up to the next biggest multiple of 16 for memory allocation.

The Microsoft documentation for malloc() states that:

The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object.

Objects of SIMD type must be 16-byte aligned to work best. These are packed types of 4 floats or 2 doubles (or other) that fit into the 128-bit registers of an x86 machine. If the data is not properly aligned, then loading and storing to these memory locations can lead a great loss of performance or even crashes. That's why malloc() does this. Hence the conclusion for the 16-byte alignment. Most memory allocations (including operator new) ultimately call malloc(). Not allocating a multiple of 16 bytes would just be a waste of memory that would otherwise be unused anyways.

其他提示

The Standard doesn't require it to reserve exactly what you specify, only at least what you specify:

21.4.4 basic_string capacity [string.capacity]

12/Effects: After reserve(), capacity() is greater or equal to the argument of reserve. [ Note: Calling reserve() with a res_arg argument less than capacity() is in effect a non-binding shrink request. A call with res_arg <= size() is in effect a non-binding shrink-to-fit request. —end note ]

I would have to look at the source to be 100% certain but it looks like the underlying code is reserving the amount you requested and padding that to the next 16 byte boundary (leaving 1 for null termination) This is just a theory based on the behavior.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top