strstream to sstream notes
The <strstream> (no .h) header is given a somewhat curious treatment in
the C++ standard (compared to the others defined there): it's relegated to
a normative appendix, section D.7. Appendix D begins:
- This clause describes features of the C++ Standard that are
specified for compatibility with existing implementations.
- These are deprecated features, where deprecated is defined as:
Normative for the current edition of the Standard, but not guaranteed
to be part of the Standard in future revisions.
So strstream/ostrstream/istrstream are required to be provided (in
namespace std). g++ is warning you that they may be taken away someday,
along with the other things in that appendix (some of which can also be
found in BaBar code).
The replacements are from <sstream>, section 27.7 of the
standard, classes [i,o]stringstream, which in general replace a stream
interface to C-strings with a stream interface to perform formatted
I/O to/from std::string values. In most cases this is a simple
migration and leads to better code, especially when creating a string
from formatted output.
For istringstream, the migrations are essentially trivial -- you
initialize an istringstream with an std::string value, and then you just
read from it as you would from an istrstream.
For ostringstream there are some important differences. Probably the most
common use of ostrstream in BaBar is with its default constructor, setting
up a dynamically allocated char* buffer to which you can write formatted
output. When you want to use that output you generally want access to it
as a C-string. A multi-step process was required in order to do that with
ostrstream:
- Terminate the C-string by writing a null byte to it (with
"myStream << ends;".
- Obtain a pointer to the C-string by calling the stream's str()
function. This transfers ownership of the buffer to the caller,
but in a weird way: although the ostrstream can no longer allocate
or free it, and its destructor won't delete it, the pre-standard
traditions for C++ failed to specify how the caller could free it
correctly herself (i.e., whether it was with delete[] or with
free()). Therefore, this further step was required:
- Before allowing the ostrstream to go out of scope, make the member
function call freeze(false) (freeze(0) in early C++) on it, to
return ownership of the buffer to the ostrstream.
Because of the funny lifetime issues, and the fact that C-strings are
inherently passed-by-reference objects, there were lots of opportunities
for lifetime errors here, memory leaks being the least of them -- e.g.,
if the pointer from str() was passed to some interface that retained
the pointer instead of copying the string.
All three of these steps are replaced for ostringstream with a single call
to "std::stream str() const" -- i.e. a call that returns a string _by
value_. No "ends" is required or even appropriate, because C++ strings
aren't null-terminated in the first place. And no "unfreezing" is needed
or possible.
This usually produces much cleaner code and mostly makes the
<strstream> -> <sstream> migration well worth it. In
plenty of places in old code, the need to remember to
unfreeze after str() produces awkward code that tries to remember that
fact through various if's and alternate return paths.
While this eliminates memory leaks, of course lifetime errors can still be
made all too easily. In
{
ostringstream oss;
oss << stuff;
f( oss.str() );
}
one must be aware that the string returned from str() is a temporary, with
expression lifetime, and that f() had better not try to hang on to a
reference to it. If f() happens to be a legacy interface that takes a
C-string, which might easily have been paired with ostrstream's "char*
str()" interface, this is even worse:
const char* cp = 0;
{
ostringstream oxx;
oss << stuff;
f( oss.str().c_str() );
// or, worse yet:
cp = oss.str().c_str();
}
/* some use of cp */
if f() doesn't either just use&discard, or copy, the string, this
is bad news.
Another important difference is that one cannot use an ostringstream to
control formatted writes to an existing (C-)string or other character
buffer. There are uses of this in BaBar, and there is no directly
equivalent way to use ostringstream -- a rewrite in terms of std::string
is needed and may result in strings being copied in some cases.
|