The Artima Developer Community
Sponsored Link

The C++ Source
Stream Thy Strings
by Bjorn Karlsson and Matthew Wilson
May 28, 2005

<<  Page 3 of 3

Advertisement

More Streams at Your Service

We've talked quite a bit about std::ostringstream, but it's not the only string stream in IOStreams; it is complemented by std::istringstream for input, and std::stringstream for both input and output. The following example demonstrates a simple use of istringstream to extract data from a string:
  #include <sstream>
  #include <string>
  #include <cassert>

  int main()
  {
    std::istringstream stm;
    stm.str("1 3.14159265 Two strings");
    int i;
    double d;
    std::string s1,s2;

    stm >> i >> d >> s1 >> s2;

    assert(i==1);
    assert(d==3.14159265);
    assert(s1=="Two");
    assert(s2=="strings");
  }
As you can see in the example, the istringstream is assigned a string that is subsequently used to extract data from; an int, a double, and two strings. By default, istringstream skips whitespace; if you need to change that behavior you can use the manipulator std::noskipws.

The remaining class, std::stringstream, does both input and output streaming. When using these streams, it makes sense to always use the stream with the capabilities you are looking for. This makes it easier to read and understand the code, so if all you need is input (string) streaming, use std::istringstream rather than always going with std::stringstream for convenience. (Remember, what may be convenient at the time of writing may not be convenient when the same code needs to be maintained.)

When Streaming Fails

Note that just like the other streams in IOStreams, the string streams defaults to handling errors by setting the stream state. The following example demonstrates how to detect and handle such errors:
  #include <sstream>
  #include <string>
  #include <cassert>
  #include <iostream>

  int main()
  {
    std::istringstream stm;
    stm >> std::noskipws; // Don't skip whitespace
    stm.str(" 1.23");
    double d;
    stm >> d;
    if (!stm)
    {
      std::cout << "Error streaming to d!\n";
      // Manually fix the problem...assuming we know what went wrong!
      // In this example, we know that we must ignore whitespace,
      // so we simply clear the stream's state.
      stm.clear(std::ios::goodbit);
      // Ignore whitespace!
      stm >> std::skipws;
      stm >> d;
    }

    assert(d==1.23);
}
In the example, the extraction of a double will fail on the first attempt; because there's no way a space can be converted to a double. This leaves the stream in a bad state (std::ios::failbit will be set), which is why the test if (!stm) yields true. Once a stream has gone bad, you must explicitly set it in a good state to be able to use it again. In this example, we know what's gone wrong, and we decide to turn on the skipping of spaces again, which nicely resolves the problem. Then, and only then, can we successfully extract the double!

Checking the stream's state can be tedious and is easy to forget. An alternative is to tell the stream to use exceptions when entering a bad state. This is done through a member function called exceptions, which accepts an argument that denotes which bad states should cause an exception to be thrown. The recommended mask includes the flags badbit and failbit. Here's the above example in a version using exceptions:

  #include <sstream>
  #include <string>
  #include <cassert>
  #include <iostream>

  int main()
  {
    std::istringstream stm;
    stm >> std::noskipws; // Don't skip whitespace
    stm.str(" 1.23");
    double d;
    try
    {
      // Turn on exceptions
      stm.exceptions(std::ios::badbit | std::ios::failbit);
      stm >> d;
    }
    catch(std::ios_base::failure e)
    {
      std::cout << e.what() << '\n';
      // Manually fix it...assuming we know what went wrong!
      stm.clear(std::ios::goodbit);
      // Ignore whitespace!
      stm >> std::skipws;
      stm >> d;
    }

    assert(d==1.23);
  }
Whether to use exceptions or not when streams end up in a bad state largely depends on the problem at hand. Our advice is to consider how a stream in a bad state affects your code, and if failure indicates a truly exceptional situation, then the exception-throwing version is definitely better.

Summary

In this article, we have looked at a suite of very useful classes from IOStreams; std::ostringstream, std::istringstream and std::stringstream. In most cases (and when you're not in need of blistering performance [6,7]), rather than searching for a suitable (specialized) conversion function, this stream type can be used to convert most anything to its string representation. This led us to another important topic, namely enabling your own classes to work seamlessly with output streams by making them OutputStreamable. Finally, we looked at other string stream offerings from the C++ Standard Library. Conversions from various types to strings are ubiquitous in most any application, which means that all the measurements we take to simplify such conversions bring forth excellent value. Input streaming, which was only briefly discussed here, is just as important as output streaming—that will be the topic of a future article.

We hope that the tools covered in this article helps you feel empowered to do what the title says—Stream Thy Strings!

Thank you for reading,
Bjorn Karlsson and Matthew Wilson

Acknowledgements

We would like to thank Kevlin Henney for his helpful comments on the first draft of this article.

Notes and References

  1. Although the wording in the Standard is Input/output library. To add to the terminological ambiguity, the C standard uses the term Streams (C-99: 7.19.2) to refer to the FILE* family of functions.
  2. The C++ Standard Library: A Tutorial and Reference, Nicolai Josuttis (Addison-Wesley, 1999).
  3. The STLSoft libraries provide freely available STL-like extensions, including STL-style wrappers for common operating system and framework APIs (such as Windows, Unix, ACE, ATL, COM, MFC, .NET, XML).
  4. OutputStreamable is the novel appellation for types that support streaming to output streams.
  5. C++ IOStreams and Locales: Advanced Programmer's Guide and Reference, Angelika Langer and Klaus Kreft (Addison-Wesley, 2000).
  6. "Flexible C++ #3: Efficient Integer To String Conversion, part 4", Matthew Wilson, C/C++ Users Journal Experts Forum, January 2004.
  7. Imperfect C++, Matthew Wilson, Addison-Wesley, 2004.

About the Authors

Matthew Wilson is a software development consultant, contributing editor for C/C++ User's Journal, and creator of the STLSoft libraries (http://stlsoft.org/) . He is author of Imperfect C++ (Addison-Wesley, 2004), and is currently working on his next two books, one of which is not about C++. Matthew's appetite for coding challenges is matched only by his appetite for chocolate; he keeps them in check by writing articles and riding his bike (not always at the same time). He can be contacted via http://imperfectcplusplus.com/.

Bjorn Karlsson is proud to be a C++ designer, programmer, teacher, preacher, and student. He has finally learned enough about C++ to realize how little he knows. When not reading or writing articles, books, or code, he has the privilege to be a part of the Boost community, and a member of The C++ Source Advisory Board. His book, Beyond The C++ Standard Library: An Introduction to Boost, will be published by Addison-Wesley in 2005. He appreciates it when people send him interesting emails at bjorn.karlsson@readsoft.com.

Bjorn and Matthew keep a reasonably up-to-date listing of their publications at http://bigboyandrunningbear.com/.

<<  Page 3 of 3


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us