Despite being simple on the outside, std::string
is a surprisingly complex type and WinDbg just doesn't have the smarts to display it in a more human-readable format.
Hovering over it in WinDbg shows something like this:

And, that's not helpful at all.
Luckily, the data is there, we just have to dig for it. In our case, the string
's value is hiding in the _Bx
member. We can get to it by running dt -r3 myString
. This will recursively print the members of myString
to the console (up to 3 levels).
0:000> dt -r3 myString
Local var @ 0x23fd90 Type std::basic_string<char,std::char_traits<char>,std::allocator<char> >
+0x000 _Myproxy : 0x00445638 std::_Container_proxy
+0x000 _Mycont : 0x0023fd90 std::_Container_base12
+0x000 _Myproxy : 0x00445638 std::_Container_proxy
+0x000 _Mycont : 0x0023fd90 std::_Container_base12
+0x004 _Myfirstiter : (null)
+0x004 _Myfirstiter : (null)
+0x004 _Bx : std::_String_val<std::_Simple_types<char> >::_Bxty
+0x000 _Buf : [16] "test1234"
+0x000 _Ptr : 0x74736574 "--- memory read error at address 0x74736574 ---"
+0x000 _Alias : [16] "test1234"
+0x014 _Mysize : 8
+0x018 _Myres : 0xf
=00a00000 npos : 0x905a4d
It took some work, but we got there.
Some things to keep in mind:
- Understand that you are looking under the hood of the implementation of a library type. This can (and will) change at any time. The implementation in my screenshots is from VS2015 and will likely differ from other versions.
- The string's value is tucked away in the
_Bx
union as a means to implement the Small String Optimization (SSO). When the string is short enough, it will be stored in _Bx._Buf
, otherwise, it will be allocated on the free store and a pointer to it stored in _Bx._Ptr
. Don't be shocked if you see what looks like garbage data in one of them, but valid data in the other.
- This isn't a problem in Visual Studio's debugger because they have ways of visualizing types and data structures. This is done with .NATVIS files which are provided by Visual Studio for common types like
std::string
.