Reputation: 1095
Consider:
std::string s_a, s_b;
std::stringstream ss_1, ss_2;
// at this stage:
// ss_1 and ss_2 have been used and are now in some strange state
// s_a and s_b contain non-white space words
ss_1.str( std::string() );
ss_1.clear();
ss_1 << s_a;
ss_1 << s_b;
// ss_1.str().c_str() is now the concatenation of s_a and s_b,
// <strike>with</strike> without space between them
ss_2.str( s_a );
ss_2.clear();
// ss_2.str().c_str() is now s_a
ss_2 << s_b; // line ***
// ss_2.str().c_str() the value of s_a is over-written by s_b
//
// Replacing line *** above with "ss_2 << ss_2.str() << " " << s_b;"
// results in ss_2 having the same content as ss_1.
Questions:
What is the difference between stringstream.str( a_value ); and stringstream << a_value; and, specifically, why does the first not allow concatenation via << but the second does?
Why did ss_1 automatically get white-space between s_a and s_b, but
do we need to explicitly add white space in the line that could
replace line ***: ss_2 << ss_2.str() << " " << s_b;
?
Upvotes: 13
Views: 2747
Reputation: 45470
Suggest you read stringstream reference: http://en.cppreference.com/w/cpp/io/basic_stringstream
std::stringstream::str()
Replaces the contents of the underlying string
operator<<
Inserts data into the stream.
Upvotes: 3
Reputation: 28699
The problem you're experiencing is because std::stringstream
is constructed by default with ios_base::openmode mode = ios_base::in|ios_base::out
which is a non-appending mode.
You're interested in the output mode here (ie: ios_base::openmode mode = ios_base::out
)
std::basic_stringbuf::str(const std::basic_string<CharT, Traits, Allocator>& s)
operates in two different ways, depending on the openmode
:
mode & ios_base::ate == false
: (ie: non-appending output streams):
str
will set pptr() == pbase()
, so that subsequent output will overwrite the characters copied from s
mode & ios_base::ate == true
: (ie: appending output streams):
str
will set pptr() == pbase() + s.size()
, so that subsequent output will be appended to the last character copied from s
(Note that this appending mode is new since c++11)
More details can be found here.
If you want the appending behaviour, create your stringstream
with ios_base::ate
:
std::stringstream ss(std::ios_base::out | std::ios_base::ate)
Simple example app here:
#include <iostream>
#include <sstream>
void non_appending()
{
std::stringstream ss;
std::string s = "hello world";
ss.str(s);
std::cout << ss.str() << std::endl;
ss << "how are you?";
std::cout << ss.str() << std::endl;
}
void appending()
{
std::stringstream ss(std::ios_base::out | std::ios_base::ate);
std::string s = "hello world";
ss.str(s);
std::cout << ss.str() << std::endl;
ss << "how are you?";
std::cout << ss.str() << std::endl;
}
int main()
{
non_appending();
appending();
exit(0);
}
This will output in the 2 different ways as explained above:
hello world
how are you?
hello world
hello worldhow are you?
Upvotes: 7