|
|
|
Sponsored Link •
|
|
Advertisement
|
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.)
#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.
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
FILE* family of functions.
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/.
|
Sponsored Links
|