And you'll love std::string, since that'll save you countless "strdup" calls and null checks. std::string also has some extra powers that make him way more useful than character buffer manipulation, but still less amazing (and heavy) than std::stringstream.
Anyway, you'll also quickly find that most functions don't accept std::stringstream or std::string; rather, they accept "const char*", which is fine by me. In fact, std::string has a "c_str" function that will return just such a pointer, and std::stringstream has a "str" function that will return a std::string, so that's great, right?
Yes, absolutely.
But watch out!
But watch out for this://! This is our string stream; we're just going to put something
//! in it for fun. This example will use a made-up connection string.
std::stringstream myStringStream;
// Set up the "connection string"; note for example purposes that
// these could be variables of any type; much like the thing at the
// end is an integer.
myStringStream << "tcp://" << "localhost" << ":" << 9001;
// Create a character pointer so that another function can use it.
const char* myPointer = myStringStream.str().c_str();
// Use that in some function.
someCStyleFunction( myPointer );
Did you see the problem?
When "myPointer" was created, it called "c_str" on a string that was only alive for the duration of that line. After that line is over, the string that generated the character pointer has been deleted; thus, the pointer to its data is invalid.
Valgrind will complain about this as accessing some memory that was deleted by the destructor of std::string, but you'll probably be too confused to realize what's going on.
In a single-threaded situation, you might be able to slide by without noticing this because nothing has used that memory just yet. However, in a multi-threaded situation, that memory is essentially instantly whisked up by other threads for other uses. And now your character pointer points to random other data. Welcome to what might be hours of troubleshooting and debugging.
The proper solution
Since "c_str" returns a pointer to the internal buffer of a std::string, and since you don't have to free it, it means that the character pointer that it returns is only valid for the lifetime of the std::string that it came from.
Our earlier example could be addressed in one of two ways.
The sneaky way
Don't let the std::string go out of scope by ending the line. The "str" function's result, a std::string, won't be cleaned up until after "someCStyleFunction" completes, so this gets around the problem. However, later expansion or debugging of the code might inadvertantly re-introduce it. Avoid this method.
//! This is our string stream; we're just going to put something
//! in it for fun. This example will use a made-up connection string.
std::stringstream myStringStream;
// Set up the "connection string"; note for example purposes that
// these could be variables of any type; much like the thing at the
// end is an integer.
myStringStream << "tcp://" << "localhost" << ":" << 9001;
//! in it for fun. This example will use a made-up connection string.
std::stringstream myStringStream;
// Set up the "connection string"; note for example purposes that
// these could be variables of any type; much like the thing at the
// end is an integer.
myStringStream << "tcp://" << "localhost" << ":" << 9001;
someCStyleFunction( myStringStream.str().c_str() );
The classy way
Actually store the std::string so that it goes out of scope when you want it to. This makes it clear what the string is for and what its scope is.
//! This is our string stream; we're just going to put something
//! in it for fun. This example will use a made-up connection string.
std::stringstream myStringStream;
// Set up the "connection string"; note for example purposes that
// these could be variables of any type; much like the thing at the
// end is an integer.
myStringStream << "tcp://" << "localhost" << ":" << 9001;
//! in it for fun. This example will use a made-up connection string.
std::stringstream myStringStream;
// Set up the "connection string"; note for example purposes that
// these could be variables of any type; much like the thing at the
// end is an integer.
myStringStream << "tcp://" << "localhost" << ":" << 9001;
//! This is the string that we have created with our string stream.
std::string myString = myStringStream.str();
// Create a character pointer so that another function can use it.
const char* myPointer = myString.c_str();
// Use that in some function.
someCStyleFunction( myPointer );
Hopefully this might save you some time. I spent hours researching the thread-safety of the STL for my current g++ version and was lead down all kinds of wrong paths for a simple, simple scoping issue.