I run a small test program to verify that our tool benefits from SSO:
// Example program
#include <iostream>
#include <string>
int main()
{
std::cout << sizeof(std::string) << " " << std::string().capacity() << std::endl;
}
Now I am a little bit puzzled by the result: Why does std::string only have a short capacity of 15 bytes, but a memory size of 32? Since 1 byte is a tag, I'd expect a short string length of 31 bytes in that case. What happens to the remaining 16 bytes?
edit: I have digged up the source code.
struct _Alloc_hider : allocator_type // TODO check __is_final
{
#if __cplusplus < 201103L
_Alloc_hider(pointer __dat, const _Alloc& __a = _Alloc())
: allocator_type(__a), _M_p(__dat) { }
#else
_Alloc_hider(pointer __dat, const _Alloc& __a)
: allocator_type(__a), _M_p(__dat) { }
_Alloc_hider(pointer __dat, _Alloc&& __a = _Alloc())
: allocator_type(std::move(__a)), _M_p(__dat) { }
#endif
pointer _M_p; // The actual data.
};
_Alloc_hider _M_dataplus;
size_type _M_string_length;
enum { _S_local_capacity = 15 / sizeof(_CharT) };
union
{
_CharT _M_local_buf[_S_local_capacity + 1];
size_type _M_allocated_capacity;
};
As you can see, the members _M_dataplus and _M_string_length are outside of the sso union. Together they take 16 bytes (8 for the pointer and 8 for the size). But why is it designed that way? Why not put _M_allocated_capacity into _Alloc_hider and make that part of the union.