(I believe this was often true for std::string implementations before C++11, but apparently C++11 made it a requirement.)
(I believe this was often true for std::string implementations before C++11, but apparently C++11 made it a requirement.)
A string implementation will typically store this as a structure with size + capacity + content pointer, with the content having a nil terminator. You could technically put capacity as a prefix of the content as well (I believe one of the apple GC string representations stores capacity as well as a reference count in the content block, and uses the reference count to determine exclusive ownership for inline mutation.)
These may have two other representations: - size, capacity and content all initialized to zero is the only representation of the empty string
- a embedded flag (such as a tagged contents pointer) indicates that instead the string holds inlined data.
In this inlined case on a 64-bit platform, you have 24 bytes to work with. You store the length in the LSB byte of the content pointer (making sure not to interfere with the tagging), and capacity is hard coded and omitted. You then have 23 bytes to work with, which would be 23 bytes of content - but you need to remember to add space for a nil byte at the end of the inlined content, bringing your capacity down to 22.
This is only true post C++11, I believe. C++03 was much more permissive about how std::strings were laid out internally.