The stream metaphor takes a bit of getting used to. At first, streams may seem more complex than traditional C-style I/O, such as printf()
. In reality, they seem complicated initially only because there is a deeper metaphor behind streams than there is behind printf()
. Don’t worry, though; after a few examples, you’ll never look back.
Chapter 1 compares the cout
stream to a laundry chute for data. You throw some variables down the stream, and they are written to the user’s screen, or console. More generally, all streams can be viewed as data chutes. Streams vary in their direction and their associated source or destination. For example, the cout
stream that you are already familiar with is an output stream, so its direction is “out.” It writes data to the console so its associated destination is “console.” The c
in cout
does not stand for “console” as you might expect, but stands for “character” as it’s a character-based stream. There is another standard stream called cin
that accepts input from the user. Its direction is “in,” and its associated source is “console.” As with cout
, the c
in cin
stands for “character.” Both cout
and cin
are predefined instances of streams that are defined within the std
namespace in C++. The following table gives a brief description of all predefined streams.
The difference between buffered and unbuffered streams is that a buffered stream does not immediately send the data to the destination, but instead, it buffers incoming data and then sends it in blocks. An unbuffered stream, on the other hand, immediately sends the data to the destination. Buffering is usually done to improve performance, as certain destinations, such as files, perform better when writing bigger blocks at once. Note that you can always force a buffered stream to send all its currently buffered data to the destination by flushing its buffer using the flush()
method.
STREAM | DESCRIPTION |
cin |
An input stream, reads data from the “input console.” |
cout |
A buffered output stream, writes data to the “output console.” |
cerr |
An unbuffered output stream, writes data to the “error console,” which is often the same as the “output console.” |
clog |
A buffered version of cerr . |
There are also wide-character versions available of these streams: wcin
, wcout
, wcerr
, and wclog
. Wide characters are discussed in Chapter 19.
Note that graphical user interface applications normally do not have a console; that is, if you write something to cout
, the user will not see it. If you are writing a library, you should never assume the existence of cout
, cin
, cerr
, or clog
because you never know whether your library will be used in a console or in a GUI application.
Another important aspect of streams is that they include data but also have a so-called current position. The current position is the position in the stream where the next read or write operation will take place.
Streams as a concept can be applied to any object that accepts data or emits data. You could write a stream-based network class or stream-based access to a MIDI-based instrument. In C++, there are three common sources and destinations for streams: console, file, and string.
You have already read many examples of user, or console, streams. Console input streams make programs interactive by allowing input from the user at run time. Console output streams provide feedback to the user and output results.
File streams, as the name implies, read data from and write data to a file system. File input streams are useful for reading configuration data and saved files, or for batch processing file-based data. File output streams are useful for saving state and providing output. File streams subsume the functionality of the C functions fprintf()
, fwrite()
, and fputs()
for output, and fscanf()
, fread()
, and fgets()
for input.
String streams are an application of the stream metaphor to the string type. With a string stream, you can treat character data just as you would treat any other stream. For the most part, this is merely a handy syntax for functionality that could be handled through methods on the string
class. However, using stream syntax provides opportunities for optimization and can be far more convenient and more efficient than direct use of the string
class. String streams subsume the functionality of sprintf()
, sprintf_s()
, sscanf()
, and other forms of C string-formatting functions.
The rest of this section deals with console streams (cin
and cout
). Examples of file and string streams are provided later in this chapter. Other types of streams, such as printer output or network I/O, are often platform dependent, so they are not covered in this book.
Output using streams is introduced in Chapter 1 and is used in almost every chapter in this book. This section briefly revisits some of the basics and introduces material that is more advanced.
Output streams are defined in the <ostream
> header file. Most programmers include <iostream
> in their programs, which in turn includes the headers for both input streams and output streams. The <iostream
> header also declares all predefined stream instances: cout
, cin
, cerr
, clog
, and the wide versions.
The <<
operator is the simplest way to use output streams. C++ basic types, such as int
s, pointers, double
s, and characters, can be output using <<
. In addition, the C++ string
class is compatible with <<
, and C-style strings are properly output as well. Following are some examples of using <<
:
int i = 7;
cout << i << endl;
char ch = 'a';
cout << ch << endl;
string myString = "Hello World.";
cout << myString << endl;
The output is as follows:
7
a
Hello World.
The cout
stream is the built-in stream for writing to the console, or standard output. You can “chain” uses of <<
together to output multiple pieces of data. This is because the <<
operator returns a reference to the stream as its result so you can immediately use <<
again on the same stream. Here is an example:
int j = 11;
cout << "The value of j is " << j << "!" << endl;
The output is as follows:
The value of j is 11!
C++ streams correctly parse C-style escape sequences, such as strings that contain
. You can also use std::endl
to start a new line. The difference between using
and endl
is that
just starts a new line while endl
also flushes the buffer. Watch out with endl
because too many flushes might hurt performance. The following example uses endl
to output and flush several lines of text with just one line of code:
cout << "Line 1" << endl << "Line 2" << endl << "Line 3" << endl;
The output is as follows:
Line 1
Line 2
Line 3
The <<
operator is, without a doubt, the most useful part of output streams. However, there is additional functionality to be explored. If you look at the <ostream>
header file, you’ll see many lines of overloaded definitions of the <<
operator to support outputting all kinds of different data types. You’ll also find some useful public methods.
put()
and write()
are raw output methods. Instead of taking an object or variable that has some defined behavior for output, put()
accepts a single character, while write()
accepts a character array. The data passed to these methods is output as is, without any special formatting or processing. For example, the following code snippet shows how to output a C-style string to the console without using the <<
operator:
const char* test = "hello there ";
cout.write(test, strlen(test));
The next snippet shows how to write a single character to the console by using the put()
method:
cout.put('a');
When you write to an output stream, the stream does not necessarily write the data to its destination right away. Most output streams buffer, or accumulate data instead of writing it out as soon as it comes in. This is usually done to improve performance. Certain stream destinations, such as files, are much more performant if data is written in larger blocks, instead of for example character-by-character. The stream flushes, or writes out the accumulated data, when one of the following conditions occurs:
endl
marker, is reached.cin
for input, cout
will flush). In the section, “File Streams,” you will learn how to establish this type of link.One way to explicitly tell a stream to flush is to call its flush()
method, as in the following code:
cout << "abc";
cout.flush(); // abc is written to the console.
cout << "def";
cout << endl; // def is written to the console.
Output errors can arise in a variety of situations. Perhaps you are trying to open a non-existing file. Maybe a disk error has prevented a write operation from succeeding, for example, because the disk is full. None of the streams’ code you have read up until this point has considered these possibilities, mainly for brevity. However, it is vital that you address any error conditions that occur.
When a stream is in its normal usable state, it is said to be “good.” The good()
method can be called directly on a stream to determine whether or not the stream is currently good.
if (cout.good()) {
cout << "All good" << endl;
}
The good()
method provides an easy way to obtain basic information about the validity of the stream, but it does not tell you why the stream is unusable. There is a method called bad()
that provides a bit more information. If bad()
returns true
, it means that a fatal error has occurred (as opposed to any nonfatal condition like end-of-file, eof()
). Another method, fail()
, returns true
if the most recent operation has failed; however, it doesn’t say anything about the next operation, which can either succeed or fail as well. For example, after calling flush()
on an output stream, you could call fail()
to make sure the flush was successful.
cout.flush();
if (cout.fail()) {
cerr << "Unable to flush to standard out" << endl;
}
Streams have a conversion operator to convert to type bool
. This conversion operator returns the same as calling !fail()
. So, the previous code snippet can be rewritten as follows:
cout.flush();
if (!cout) {
cerr << "Unable to flush to standard out" << endl;
}
Important to know is that both good()
and fail()
return false
if the end-of-file is reached. The relation is as follows: good()
==
(!fail()
&&
!eof())
.
You can also tell the streams to throw exceptions when a failure occurs. You then write a catch
handler to catch ios_base::failure
exceptions, on which you can use the what()
method to get a description of the error, and the code()
method to get the error code. However, whether or not you get useful information depends on the Standard Library implementation that you use.
cout.exceptions(ios::failbit | ios::badbit | ios::eofbit);
try {
cout << "Hello World." << endl;
} catch (const ios_base::failure& ex) {
cerr << "Caught exception: " << ex.what()
<< ", error code = " << ex.code() << endl;
}
To reset the error state of a stream, use the clear()
method:
cout.clear();
Error checking is performed less frequently for console output streams than for file output or input streams. The methods discussed here apply for other types of streams as well and are revisited later as each type is discussed.
One of the unusual features of streams is that you can throw more than just data down the chute. C++ streams also recognize manipulators, objects that make a change to the behavior of the stream instead of, or in addition to, providing data for the stream to work with.
You have already seen one manipulator: endl
. The endl
manipulator encapsulates data and behavior. It tells the stream to output an end-of-line sequence and to flush its buffer. Following are some other useful manipulators, many of which are defined in the <ios>
and <iomanip>
standard header files. The example after this list shows how to use them.
bool
values as true and false (boolalpha
) or 1 and 0 (noboolalpha
). The default is noboolalpha
.All of these manipulators stay in effect for subsequent output to the stream until they are reset, except setw
, which is only active for the next single output. The following example uses several of these manipulators to customize its output:
// Boolean values
bool myBool = true;
cout << "This is the default: " << myBool << endl;
cout << "This should be true: " << boolalpha << myBool << endl;
cout << "This should be 1: " << noboolalpha << myBool << endl;
// Simulate "%6d" with streams
int i = 123;
printf("This should be ' 123': %6d ", i);
cout << "This should be ' 123': " << setw(6) << i << endl;
// Simulate "%06d" with streams
printf("This should be '000123': %06d ", i);
cout << "This should be '000123': " << setfill('0') << setw(6) << i << endl;
// Fill with *
cout << "This should be '***123': " << setfill('*') << setw(6) << i << endl;
// Reset fill character
cout << setfill(' ');
// Floating point values
double dbl = 1.452;
double dbl2 = 5;
cout << "This should be ' 5': " << setw(2) << noshowpoint << dbl2 << endl;
cout << "This should be @@1.452: " << setw(7) << setfill('@') << dbl << endl;
// Reset fill character
cout << setfill(' ');
// Instructs cout to start formatting numbers according to your location.
// Chapter 19 explains the details of the imbue call and the locale object.
cout.imbue(locale(""));
// Format numbers according to your location
cout << "This is 1234567 formatted according to your location: " << 1234567
<< endl;
// Monetary value. What exactly a monetary value means depends on your
// location. For example, in the USA, a monetary value of 120000 means 120000
// dollar cents, which is 1200.00 dollars.
cout << "This should be a monetary value of 120000, "
<< "formatted according to your location: "
<< put_money("120000") << endl;
// Date and time
time_t t_t = time(nullptr); // Get current system time
tm* t = localtime(&t_t); // Convert to local time
cout << "This should be the current date and time "
<< "formatted according to your location: "
<< put_time(t, "%c") << endl;
// Quoted string
cout << "This should be: "Quoted string with \"embedded quotes\".": "
<< quoted("Quoted string with "embedded quotes".") << endl;
If you don’t care for the concept of manipulators, you can usually get by without them. Streams provide much of the same functionality through equivalent methods like precision()
. For example, take the following line:
cout << "This should be '1.2346': " << setprecision(5) << 1.23456789 << endl;
This can be converted to use a method call as follows. The advantage of the method calls is that they return the previous value, allowing you to restore it, if needed.
cout.precision(5);
cout << "This should be '1.2346': " << 1.23456789 << endl;
For a detailed description of all stream methods and manipulators, consult a Standard Library Reference, for example, the book C++ Standard Library Quick Reference, or online references http://www.cppreference.com/
or http://www.cplusplus.com/reference/
.
Input streams provide a simple way to read in structured or unstructured data. In this section, the techniques for input are discussed within the context of cin
, the console input stream.
There are two easy ways to read data by using an input stream. The first is an analog of the <<
operator that outputs data to an output stream. The corresponding operator for reading data is >>
. When you use >>
to read data from an input stream, the variable you provide is the storage for the received value. For example, the following program reads one word from the user and puts it into a string. Then the string is output back to the console.
string userInput;
cin >> userInput;
cout << "User input was " << userInput << endl;
By default, the >>
operator tokenizes values according to white space. For example, if a user runs the previous program and enters hello there
as input, only the characters up to the first white space character (the space character in this instance) are captured into the userInput
variable. The output would be as follows:
User input was hello
One solution to include white space in the input is to use get()
, which is discussed later in this chapter.
The >>
operator works with different variable types, just like the <<
operator. For example, to read an integer, the code differs only in the type of the variable:
int userInput;
cin >> userInput;
cout << "User input was " << userInput << endl;
You can use input streams to read in multiple values, mixing and matching types as necessary. For example, the following function, an excerpt from a restaurant reservation system, asks the user for a last name and the number of people in their party:
void getReservationData()
{
string guestName;
int partySize;
cout << "Name and number of guests: ";
cin >> guestName >> partySize;
cout << "Thank you, " << guestName << "." << endl;
if (partySize > 10) {
cout << "An extra gratuity will apply." << endl;
}
}
Remember that the >>
operator tokenizes values according to white space, so the getReservationData()
function does not allow you to enter a name with white space. A solution using unget()
is discussed later in this chapter. Note also that even though the use of cout
does not explicitly flush the buffer using endl
or flush()
, the text will still be written to the console because the use of cin
immediately flushes the cout
buffer; they are linked together in this way.
Input streams have a number of methods to detect unusual circumstances. Most of the error conditions related to input streams occur when there is no data available to read. For example, the end of stream (referred to as end-of-file, even for non-file streams) may have been reached. The most common way of querying the state of an input stream is to access it within a conditional. For example, the following loop keeps looping as long as cin
remains in a good state:
while (cin) { ... }
You can input data at the same time:
while (cin >> ch) { ... }
The good()
, bad()
, and fail()
methods can be called on input streams, just as on output streams. There is also an eof()
method that returns true
if the stream has reached its end. Similar as for output streams, both good()
and fail()
return false
if the end-of-file is reached. The relation is again as follows: good()
==
(!fail()
&&
!eof())
.
You should get into the habit of checking the stream state after reading data so that you can recover from bad input.
The following program shows the common pattern for reading data from a stream and handling errors. The program reads numbers from standard input and displays their sum once end-of-file is reached. Note that in command-line environments, the end-of-file is indicated by the user typing a particular character. In Unix and Linux, it is Control+D
; in Windows it is Control+Z
. The exact character is operating-system dependent, so you will need to know what your operating system requires:
cout << "Enter numbers on separate lines to add. "
<< "Use Control+D to finish (Control+Z in Windows)." << endl;
int sum = 0;
if (!cin.good()) {
cerr << "Standard input is in a bad state!" << endl;
return 1;
}
int number;
while (!cin.bad()) {
cin >> number;
if (cin.good()) {
sum += number;
} else if (cin.eof()) {
break; // Reached end of file
} else if (cin.fail()) {
// Failure!
cin.clear(); // Clear the failure state.
string badToken;
cin >> badToken; // Consume the bad input.
cerr << "WARNING: Bad input encountered: " << badToken << endl;
}
}
cout << "The sum is " << sum << endl;
Here is some example output of this program:
Enter numbers on separate lines to add. Use Control+D to finish (Control+Z in Windows).
1
2
test
WARNING: Bad input encountered: test
3
^Z
The sum is 6
Just like output streams, input streams have several methods that allow a lower level of access than the functionality provided by the more common >>
operator.
The get()
method allows raw input of data from a stream. The simplest version of get()
returns the next character in the stream, though other versions exist that read multiple characters at once. get()
is most commonly used to avoid the automatic tokenization that occurs with the >>
operator. For example, the following function reads a name, which can be made up of several words, from an input stream until the end of the stream is reached:
string readName(istream& stream)
{
string name;
while (stream) { // Or: while (!stream.fail()) {
int next = stream.get();
if (!stream || next == std::char_traits<char>::eof())
break;
name += static_cast<char>(next);// Append character.
}
return name;
}
There are several interesting observations to make about this readName()
function:
const
reference to an istream
, not a const
reference. The methods that read in data from a stream will change the actual stream (most notably, its position), so they are not const
methods. Thus, you cannot call them on a const
reference.get()
is stored in an int
, not in a char
, because get()
can return special non-character values such as std::char_traits<char>::eof()
(end-of-file).readName()
is a bit strange because there are two ways to get out of the loop: either the stream can get into a failed state, or the end of the stream is reached. A more common pattern for reading from a stream uses a different version of get()
that takes a reference to a character and returns a reference to the stream. This pattern takes advantage of the fact that evaluating an input stream within a conditional context results in true
only if the stream is not in any error state. Encountering an error causes the stream to evaluate to false
. The underlying details of the conversion operations required to implement this feature are explained in Chapter 15. The following version of the same function is a bit more concise:
string readName(istream& stream)
{
string name;
char next;
while (stream.get(next)) {
name += next;
}
return name;
}
For most purposes, the correct way to think of an input stream is as a one-way chute. Data falls down the chute and into variables. The unget()
method breaks this model in a way by allowing you to push data back up the chute.
A call to unget()
causes the stream to back up by one position, essentially putting the previous character read back on the stream. You can use the fail()
method to see if unget()
was successful or not. For example, unget()
can fail if the current position is at the beginning of the stream.
The getReservationData()
function seen earlier in this chapter did not allow you to enter a name with white space. The following code uses unget()
to allow white space in the name. The code reads character by character and checks whether the character is a digit or not. If the character is not a digit, it is added to guestName
. If it is a digit, the character is put back into the stream using unget()
, the loop is stopped, and the >>
operator is used to input an integer, partySize
. The noskipws
input manipulator tells the stream not to skip white space, that is, white space is read like any other characters.
void getReservationData()
{
string guestName;
int partySize = 0;
// Read characters until we find a digit
char ch;
cin >> noskipws;
while (cin >> ch) {
if (isdigit(ch)) {
cin.unget();
if (cin.fail())
cout << "unget() failed" << endl;
break;
}
guestName += ch;
}
// Read partysize, if the stream is not in error state
if (cin)
cin >> partySize;
if (!cin) {
cerr << "Error getting party size." << endl;
return;
}
cout << "Thank you '" << guestName
<< "', party of " << partySize << endl;
if (partySize > 10) {
cout << "An extra gratuity will apply." << endl;
}
}
The putback()
method, like unget()
, lets you move backward by one character in an input stream. The difference is that the putback()
method takes the character being placed back on the stream as a parameter:
char ch1;
cin >> ch1;
cin.putback('e');
// 'e' will be the next character read off the stream.
The peek()
method allows you to preview the next value that would be returned if you were to call get()
. To take the chute metaphor perhaps a bit too far, you could think of it as looking up the chute without a value actually falling down it.
peek()
is ideal for any situation where you need to look ahead before reading a value. For example, the following code implements the getReservationData()
function that allows white space in the name, but uses peek()
instead of unget()
:
void getReservationData()
{
string guestName;
int partySize = 0;
// Read characters until we find a digit
char ch;
cin >> noskipws;
while (true) {
// 'peek' at next character
ch = static_cast<char>(cin.peek());
if (!cin)
break;
if (isdigit(ch)) {
// next character will be a digit, so stop the loop
break;
}
// next character will be a non-digit, so read it
cin >> ch;
if (!cin)
break;
guestName += ch;
}
// Read partysize, if the stream is not in error state
if (cin)
cin >> partySize;
if (!cin) {
cerr << "Error getting party size." << endl;
return;
}
cout << "Thank you '" << guestName
<< "', party of " << partySize << endl;
if (partySize > 10) {
cout << "An extra gratuity will apply." << endl;
}
}
Obtaining a single line of data from an input stream is so common that a method exists to do it for you. The getline()
method fills a character buffer with a line of data up to the specified size. The specified size includes the