最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - How to resize a std::string and have it have the same capacity? - Stack Overflow

programmeradmin3浏览0评论

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
  • 1 realistically your allocator is never going to give you 17 bytes, it will allocate 32 or 64 bytes to serve your allocation, shrinking it to 17 doesn't change how much memory needs to be allocated, i think they round to 31 so that 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:48
  • Short String Optimization is going to get in your way. Until you run out of SSO space the capacity is going to be some fixed small value in the teens to 30's depending on the implementation. – NathanOliver Commented Mar 15 at 23:48
  • 1 All thre compilers have a std::string size of 32 so as long as its less than that it can fit in the string object. – NathanOliver Commented Mar 15 at 23:54
  • 1 @Zebrafish clang with libc++ gives you 22, because that's its SSO size godbolt./z/YnjYnEfs5 , the other 2 only have 15 bytes of SSO – Ahmed AEK Commented Mar 15 at 23:57
  • 1 @Zebrafish there are many of tricks to store up to 23 characters per 24 bytes of the object because there are always free bits in the pointers – phuclv Commented Mar 16 at 1:04
 |  Show 7 more comments

2 Answers 2

Reset to default 7

The 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

发布评论

评论列表(0)

  1. 暂无评论