4

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)

1
  • 10
    Because it's not required to. It shouldn't matter to you if it can allocate more efficiently. Commented Jul 8, 2013 at 14:30

3 Answers 3

8

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.

Sign up to request clarification or add additional context in comments.

Comments

5

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 ]

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.