Source code
#include <string> int main() { std::string s = "Hello World"; const char* cs = s.c_str(); return 0; }
Analysis
$ g++ --version g++ (Ubuntu 13.2.0-4ubuntu3) 13.2.0 $ g++ main.cpp -g $ gdb a.out (gdb) b 7 (gdb) r (gdb) disable pretty-printer (gdb) p /x s $1 = { _M_dataplus = {..., _M_p = 0x7fffffffde30}, _M_string_length = 0xb, {_M_local_buf = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0}, _M_allocated_capacity = 0x6f57206f6c6c6548}} (gdb) p sizeof(s) $2 = 32 (gdb) x/4xg &s 0x7fffffffde20: 0x00007fffffffde30 0x000000000000000b 0x7fffffffde30: 0x6f57206f6c6c6548 0x0000000000646c72 (gdb) x/1s s._M_dataplus._M_p 0x7fffffffde30: "Hello World" (gdb) x/1s cs 0x7fffffffde30: "Hello World"
Here the payload is on the stack (small string optimization), but if ‘_M_string_length’ is greater than 15 it will be on the heap. (Source: gcc/libstdc++-v3/include/bits/basic_string.h)
The std::string payload is null-terminated (‘\0’). This seems to be useless, cause std::string stores the length, but it’s done to provide a null-terminated const char* via its method c_str().
Size comparison
char* | std::string (len ≤ 15) | std::string (len > 15) |
---|---|---|
Raw Ptr (to first char)1 + Heap buffer (payload) = 4 Byte + Payload |
Raw Ptr (to first char)1 + Length (of payload)2 + Stack buffer (payload)3 = 32 Byte |
Raw Ptr (to first char)1 + Length (of payload)2 + Stack buffer (capacity)3 + Heap buffer (payload) = 32 Byte + Payload |
On 64 Bit: 1 8 Byte, 2 8 Byte, 3 16 Byte