It's because the actual write position isn't updated, so when you in the first example do
ss << str;
you overwrite the current string.
Use the flag std::ios_base::ate
to the constructor of the string stream
std::stringstream ss(str,
std::ios_base::in | std::ios_base::out | std::ios_base::ate);
to position the read/write pointers at the end.
See the example in this reference.
And it's like that for all streams, when you open a file stream the positions are also at the start.