Increase type safety, reduce errors, improve performance, allow extensibility, and provide inheritability.
printf() is arguably not broken, and scanf() is perhaps livable despite being error prone, however both are limited with respect to what C++ I/O can do. C++ I/O (using << and >>) is, relative to C (using printf() and scanf()):
[ Top | Bottom | Previous section | Next section ]
For example, suppose you have the following code that reads integers from std::cin:
The problem with this code is that it lacks any checking to see if someone entered an invalid input character. In particular, if someone enters something that doesn't look like an integer (such as an 'x'), the stream std::cin goes into a "failed state," and all subsequent input attempts return immediately without doing anything. In other words, the program enters an infinite loop; if 42 was the last number that was successfully read, the program will print the message You entered 42 over and over.
An easy way to check for invalid input is to move the input request from the body of the while loop into the control-expression of the while loop. E.g.,
This will cause the while loop to exit either when you hit end-of-file, or when you enter a bad integer, or when you enter -1.
(Naturally you can eliminate the break by changing the while loop expression from while (std::cin >> i) to while ((std::cin >> i) && (i != -1)), but that's not really the point of this FAQ since this FAQ has to do with iostreams rather than generic structured programming guidelines.)
[ Top | Bottom | Previous section | Next section ]
See the previous FAQ for an example of the "funky while (std::cin >> foo) syntax."
The expression (std::cin >> foo) calls the appropriate operator>> (for example, it calls the operator>> that takes an std::istream on the left and, if foo is of type int, an int& on the right). The std::istream operator>> functions return their left argument by convention, which in this case means it will return std::cin. Next the compiler notices that the returned std::istream is in a boolean context, so it converts that std::istream into a boolean.
To convert an std::istream into a boolean, the compiler calls a member function called std::istream::operator void*(). This returns a void* pointer, which is in turn converted to a boolean (NULL becomes false, any other pointer becomes true). So in this case the compiler generates a call to std::cin.operator void*(), just as if you had casted it explicitly such as (void*) std::cin.
The operator void*() cast operator returns some non-NULL pointer if the stream is in a good state, or NULL if it's in a failed state. For example, if you read one too many times (e.g., if you're already at end-of-file), or if the actual info on the input stream isn't valid for the type of foo (e.g., if foo is an int and the data is an 'x' character), the stream will go into a failed state and the cast operator will return NULL.
The reason operator>> doesn't simply return a bool (or void*) indicating whether it succeeded or failed is to support the "cascading" syntax:
The operator>> is left-associative, which means the above is parsed as:
In other words, if we replace operator>> with a normal function name such as readFrom(), this becomes the expression:
As always, we begin evaluating at the innermost expression. Because of the left-associativity of operator>>, this happens to be the left-most expression, std::cin >> foo. This expression returns std::cin (more precisely, it returns a reference to its left-hand argument) to the next expression. The next expression also returns (a reference to) std::cin, but this second reference is ignored since it's the outermost expression in this "expression statement."
[ Top | Bottom | Previous section | Next section ]
Because the eof state may not get set until after a read is attempted past the end of file. That is, reading the last byte from a file might not set the eof state. E.g., suppose the input stream is mapped to a keyboard in that case it's not even theoretically possible for the C++ library to predict whether or not the character that the user just typed will be the last character.
For example, the following code might have an off-by-one error with the count i:
What you really need is:
[ Top | Bottom | Previous section | Next section ]
Because the numerical extractor leaves non-digits behind in the input buffer.
If your code looks like this:
What you really want is:
Of course you might want to change the for (;;) statement to while (std::cin), but don't confuse that with skipping the non-numeric characters at the end of the loop via the line: std::cin.ignore(...);.
[ Top | Bottom | Previous section | Next section ]
Use operator overloading to provide a friend left-shift operator, operator<<.
We use a non-member function (a friend in this case) since the Fred object is the right-hand operand of the << operator. If the Fred object was supposed to be on the left hand side of the << (that is, myFred << std::cout rather than std::cout << myFred), we could have used a member function named operator<<.
Note that operator<< returns the stream. This is so the output operations can be cascaded.
[ Top | Bottom | Previous section | Next section ]
No.
The usual reason people want to always use a printOn() method rather than a friend function is because they wrongly believe that friends violate encapsulation and/or that friends are evil. These beliefs are naive and wrong: when used properly, friends can actually enhance encapsulation.
This is not to say that the printOn() method approach is never useful. For example, it is useful when providing printing for an entire hierarchy of classes. But if you use a printOn() method, it should normally be protected, not public.
For completeness, here is "the printOn() method approach." The idea is to have a member function (often called printOn() that does the actual printing, then have operator<< call that printOn() method. When it is done wrongly, the printOn() method is public so operator<< doesn't have to be a friend it can be a simple top-level function that is neither a friend nor a member of the class. Here's some sample code:
People wrongly assume that this reduces maintenance cost "since it avoids having a friend function." This is a wrong assumption because:
Net: the member-called-by-top-level-function approach has a cost but no benefit. Therefore it is, in general, a bad idea.
Note: if the printOn() method is protected or private, the second objection doesn't apply. There are cases when that approach is reasonable, such as when providing printing for an entire hierarchy of classes. Note also that when the printOn() method is non-public, operator<< needs to be a friend.
[ Top | Bottom | Previous section | Next section ]
Use operator overloading to provide a friend right-shift operator, operator>>. This is similar to the output operator, except the parameter doesn't have a const: "Fred&" rather than "const Fred&".
Note that operator>> returns the stream. This is so the input operations can be cascaded and/or used in a while loop or if statement.
[ Top | Bottom | Previous section | Next section ]
Provide a friend operator<< that calls a protected virtual function:
The end result is that operator<< acts as if it was dynamically bound, even though it's a friend function. This is called the Virtual Friend Function Idiom.
Note that derived classes override printOn(std::ostream&) const. In particular, they do not provide their own operator<<.
Naturally if Base is an ABC, Base::printOn(std::ostream&) const can be declared pure virtual using the "= 0" syntax.
[ Top | Bottom | Previous section | Next section ]
This is implementation dependent. Check with your compiler's documentation.
For example, suppose you want to do binary I/O using std::cin and std::cout. Suppose further that your operating system (such as DOS or OS/2) insists on translating "\r\n" into "\n" on input from std::cin, and "\n" to "\r\n" on output to std::cout or std::cerr.
Unfortunately there is no standard way to cause std::cin, std::cout, and/or std::cerr to be opened in binary mode. Closing the streams and attempting to reopen them in binary mode might have unexpected or undesirable results.
On systems where it makes a difference, the implementation might provide a way to make them binary streams, but you would have to check the manuals to find out.
[ Top | Bottom | Previous section | Next section ]
Because "\t" is a tab character.
You should use forward slashes in your filenames, even on an operating system that uses backslashes such as DOS, Windows, OS/2, etc. For example:
Remember, the backslash ("\") is used in string literals to create special characters: "\n" is a newline, "\b" is a backspace, and "\t" is a tab, "\a" is an "alert", "\v" is a vertical-tab, etc. Therefore the file name "\version\next\alpha\beta\test.dat" is interpreted as a bunch of very funny characters; use "/version/next/alpha/beta/test.dat" instead, even on systems that use a "\" as the directory separator such as DOS, Windows, OS/2, etc. This is because the library routines on these operating systems handle "/" and "\" interchangeably.
[ Top | Bottom | Previous section | Next section ]
There are two easy ways to do this: you can use the <stdio> facilities or the <iostream> library. In general, you should prefer the <iostream> library.
The <iostream> library allows you to convert pretty much anything to a std::string using the following syntax (the example converts a double, but you could substitute pretty much anything that prints using the << operator):
The std::ostringstream object o offers formatting facilities just like those for std::cout. You can use manipulators and format flags to control the formatting of the result, just as you can for other std::cout.
In this example, we insert x into o via the overloaded insertion operator, <<. This invokes the iostream formatting facilities to convert x into a std::string. The if test makes sure the conversion works correctly it should always succeed for built-in types, but the if test is good style.
The expression os.str() returns the std::string that contains whatever has been inserted into stream o, in this case the string value of x.
[ Top | Bottom | Previous section | Next section ]
There are two easy ways to do this: you can use the <stdio> facilities or the <iostream> library. In general, you should prefer the <iostream> library.
The <iostream> library allows you to convert a std::string to pretty much anything using the following syntax (the example converts a double, but you could substitute pretty much anything that can be read using the >> operator):
The std::istringstream object i offers formatting facilities just like those for std::cin. You can use manipulators and format flags to control the formatting of the result, just as you can for other std::cin.
In this example, we initialize the std::istringstream i passing the std::string s (for example, s might be the string "123.456"), then we extract i into x via the overloaded extraction operator, >>. This invokes the iostream formatting facilities to convert as much of the string as possible/appropriate based on the type of x.
The if test makes sure the conversion works correctly. For example, if the string contains characters that are inappropriate for the type of x, the if test will fail.
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000