Reputation: 10911
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)
Upvotes: 4
Views: 1055
Reputation: 23600
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 abasic_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 ofreserve
. [ Note: Callingreserve()
with ares_arg
argument less thancapacity()
is in effect a non-binding shrink request. A call withres_arg <= size()
is in effect a non-binding shrink-to-fit request. — end note ]
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.
Upvotes: 8
Reputation: 380
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.
Upvotes: 0
Reputation: 101446
The Standard doesn't require it to reserve exactly what you specify, only at least what you specify:
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 ]
Upvotes: 5