SLAC PEP-II
BABAR
SLAC<->RAL
Babar logo
HEPIC E,S & H Databases PDG HEP preprints
Organization Detector Computing Physics Documentation
Personnel Glossary Sitemap Search Hypernews
Unwrap page!
Comp. Search
Who's who?
Meetings
FAQ Homepage
Archive
Environment
Administration
New User Info.
Web Info/Tools
Monitoring
Training
Tools & Utils
Programming
C++ Standard
SRT, AFS, CVS
QA and QC
Remedy
Histogramming
Operations
PromptReco
Simulation Production
Online SW
Dataflow
Detector Control
Evt Processing
Run Control
Calibration
Databases
Offline
Workbook
Coding Standards
Simulation
Reconstruction
Prompt Reco.
BaBar Grid
Data Distribution
Beta & BetaTools
Kanga & Root
Analysis Tools
RooFit Toolkit
Data Management
Data Quality
Event display
Event Browser
Code releases
Databases
Check this page for HTML 4.01 Transitional compliance with the
W3C Validator
(More checks...)

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:

  1. This clause describes features of the C++ Standard that are specified for compatibility with existing implementations.
  2. 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:

  1. Terminate the C-string by writing a null byte to it (with "myStream << ends;".
  2. 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:
  3. 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.