If I have an empty string and I do .resize() I expected the size and the capacity to be that size. That is not the case in GCC or Clang or MSVC. Requesting a size of 17 gives you a capacity of 30 or 31. And in the case of calling shrink_to_fit(17) both GCC and Clang shrink the capacity to 17, except MSVC, which does nothing and leaves it at 31.
What I want is a way to resize to a specific size and have that capacity, I don't want double the space when I asked for 17. Is this possible without shrinking to fit? I noticed there's resize_and_overwrite in C++ 23 and it behaves the same. I guess if not I need to write my own string class.
If I have an empty string and I do .resize() I expected the size and the capacity to be that size. That is not the case in GCC or Clang or MSVC. Requesting a size of 17 gives you a capacity of 30 or 31. And in the case of calling shrink_to_fit(17) both GCC and Clang shrink the capacity to 17, except MSVC, which does nothing and leaves it at 31.
What I want is a way to resize to a specific size and have that capacity, I don't want double the space when I asked for 17. Is this possible without shrinking to fit? I noticed there's resize_and_overwrite in C++ 23 and it behaves the same. I guess if not I need to write my own string class.
Share Improve this question asked Mar 15 at 23:45 ZebrafishZebrafish 15k3 gold badges66 silver badges153 bronze badges 12 | Show 7 more comments2 Answers
Reset to default 7The global allocator has to provide __STDCPP_DEFAULT_NEW_ALIGNMENT__
which is 16 bytes on 64 bit systems, the allocator needs to serve chunks of at least 16 bytes of size. and if you ask for 17 bytes the allocator has to reserve 32 bytes, even if you only ask for 17 bytes.
MSVC uses this knowledge and forces the string capacity to always be a multiple of 16, -1 for null terminator, this gives you 31 bytes when you ask for 17, shrinking only shrinks it down to the lowest multiple of 16. this comes in handy if you later push_back
into the string.
libc++, can store 22 bytes in the SSO, so it can serve those 17 bytes from SSO online demo, however if you ask for a larger size it uses the same knowledge as MSVC to keep its capacity a multiple of 8 bytes (-1 for null terminator)
libstdc++ is the odd one, it always grows to at least twice its capacity (similar to push_back
), and an empty string capacity is 15, because of SSO, so it grows to at least 30 bytes.
MSVC and libc++ behavior is near optimal.
libstdc++ is only problematic if you resize from 127 to 129 because it will grow to 254, otherwise for any size > 30 it will have the capacity you asked for if it was resized from an empty state, and for sizes <= 30 it doesn't matter because the allocator cannot give you less memory.
std::string::resize()
doesnt give you strict control over capacity as most implementations of std::string
are designed to optimise for future expansions. calling shrink_to_fit()
as far as i recall should work for GCC and Clang but not MSVC, which would be done with s.resize(17); s.shrink_to_fit();
instead i would suggest one of the following methods (in order)
method 1
std::string s;
s.reserve(17);
s.assign(17, ' ');
this method should prealloc exactly 17 bytes in all std imples
method 2 - instead of using a string, use a char vector
std::vector<char> s(17);
method 3 - last resort
implement a custom string class wrapping std::vector<char>
or std::unique_ptr<char[]>
- i will not go into details but if you do need help feel free to ask in comments
append
doesn't have to reallocate when they are already sure the allocator gave you enough space that you just didn't use. – Ahmed AEK Commented Mar 15 at 23:48std::string
size of32
so as long as its less than that it can fit in the string object. – NathanOliver Commented Mar 15 at 23:54