Currently I'm self-learning C++ Primer 5th. Here comes something I'm not sure. (I couldn't find the exact relevant question on F.A.Q).
Consider this while loop:
while(std::cin>>value){...} \\value here was defined as int.
The text book says:
That expression reads the next number from the standard input and stores that number in value. The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. This condition, therefore, tests std::cin.When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
My question is: does std::cin read input into value first then test the validation of std::cin, or test std::cin first then decide whether to read into 'value'? I'm quite confused about when it "returns its left operand".
Remember that your code is equivalent to:
while (std::cin.operator>>(value)) { }
Or:
while (1) {
std::cin >> value ;
if (!std::cin) break ;
}
The "code" always tries to read from std::cin into value before testing std::cin.
Let's look at the quote:
[...] The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. [...]
This only means that std::cin.operator>>(value) return std::cin.
This condition, therefore, tests std::cin. When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
What the text book says is that after trying to read an integer from std::cin to value, the >> operator returns std::cin. If std::cin is in a good state after reading value, then the test passes, otherwize it fails.
Some extra details:
When you do std::cin >> value, you basically call istream::operator>>(int&), and yes there is a test inside that method: If the test passes, then the internal state of std::cin is set to ios_base::goodbit, if it fails, internal state is set to on of the error flag (eofbit, failbit or badbit).
Depending on the exception mask for std::cin, if the internal test fails, an exception may be thrown.
From your quote:
When we use an istream as a condition, the effect is to test the state of the stream.
This basically mean that:
if (std::cin) { }
Is equivalent to:
if (!std::cin.fail()) { }
And std::cin.fail() check for failbit or badbit. This means that while (std::cin >> value) { } does not test the eofbit flag and will only fail when the input cannot be converted to an integer value.
does std::cin read input into value first then test the validation of
std::cin, or test std::cin first then decide whether to read into
'value'
cin first tries to read an int from the standard input, if cin is in a good state: if it fails to, it will set the stream to a bad state; regardless of the operation done, it will return the stream itself (i.e. the "left operand" -- cin), that will allow you to check for success or failure.
If you wanted to explicitly test the validity of the stream first and only then try to read the value, you would have:
while (cin && cin >> value)
but it's pretty redundant, since, as I've told you, cin will not even try to read value if it's already in a bad state.
There are two tests.
The first test is the condition of the while statement
while(std::cin>>value){...}
This condition tests the result of calling operator function operator >>
The second test is a condition within the operator. If the state of the stream std::cin is good then the function tries to read an integer from the string. Otherwise it returns std::cin with the current erroneous state of std::cin.
In the while condition there is an expression
std::cin>>value
This expression must be evaluated. So this condition tests the result of the call of operator >> .
The result of the operator is the stream std::cin But it can be contextually converted to a bool value due to operator
explicit operator bool() const;
which returns the state of the stream
!fail().
I assume your "value" is for example an int
The stream tries to read input until the next whitespace.
if eof is found ... -> then the state will be set to "eof", >> will return the stream and the boolean evaluation of the stream will return false
if an error (I/O for example) happens during the reading process, the state will be set to "bad", >> will return the stream and the boolean evaluation of the stream will return false
if whitespace has been found, then a conversion from the read characters to int (the above assumption) will be attempted. If it fails (because the read input is for example: "xx" and not a number) the state of the stream will be set to "fail". >> will return the stream and the boolean evaluation of the stream will return false
if we are so far down the chain, eof was not found, no IO error (or other) happened, and the characters -> int conversion was successful. >> will return the stream and the boolean evaluation of the stream will return true.
And your "value" will contain the appropriate value
Presumably you wouldn't have any confusion with a simple function call:
SomeReturnType some_function(int&);
while (some_function(value)) { ... }
The above code will repeatedly call some_function until the return value from the function call, interpreted as a boolean, is false. The function is called for each step in the loop. Whether the function changes the value of value is up to the function. It certainly can do so, and presumably will do so (but that's an issue for the designer of the function).
The loop while (std::cin>>value) {...} is completely equivalent to while (std::cin.operator>>(value)) {...}. This is just a function call to the member function std::stream::operator>>(int&).
The operator first reads the value and then returns a reference to the object. The while statement first calls that operator and second tests the returned value.
Related
I have a problem that cin.ignore() can not remove input from the buffer.
#include <iostream>
#include <string>
int main() {
using namespace std;
int x=0;
string k;
cin >> x;
cin.ignore(100,'\n');
cin.clear();
cin >> k;
cout << k << endl;
}
For the above code:
input : abc (program ends when I just input abc)
output : abc
I was really surprised because cin.ignore() did not remove "abc" from the input buffer.
What is wrong with my code?
If I change the positions of cin.ignore() and cin.clear(), it works well, why is that?
This code:
int x=0;
cin >> x;
Causes cin to be put into an error state (specifically, the failbit flag is set) if the input is not convertible to an int.
Per cppreference.com:
std::basic_istream<CharT,Traits>::operator>>:
This function behaves as a FormattedInputFunction. After constructing and checking the sentry object, which may skip leading whitespace, extracts an integer value by calling std::num_get::get().
...
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(until C++11)
If extraction fails, zero is written to value and failbit is set. For signed integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() (respectively) is written and failbit flag is set. For unsigned integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() is written and failbit flag is set.
(since C++11)
...
Thus, any further I/O operations on the stream are disabled, like ignore(), until you clear() the error state to re-enable I/O.
std::basic_ios<CharT,Traits>::clear:
Sets the stream error state flags by assigning them the value of state. By default, assigns std::ios_base::goodbit which has the effect of clearing all error state flags.
std::basic_istream<CharT,Traits>::ignore:
ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any of the following conditions occurs:
...
C++ named requirements: UnformattedInputFunction:
An UnformattedInputFunction is a stream input function that performs the following:
Constructs an object of type basic_istream::sentry with automatic storage duration and with the noskipws argument set to true, which performs the following
if eofbit or badbit are set on the input stream, sets the failbit as well, and if exceptions on failbit are enabled in this input stream's exception mask, throws ios_base::failure.
flushes the tie()'d output stream, if applicable
Checks the status of the sentry by calling sentry::operator bool(), which is equivalent to basic_ios::good.
If the sentry returned false or sentry's constructor threw an exception:
sets the number of extracted characters (gcount) in the input stream to zero
if the function was called to write to an array of CharT, writes CharT() (the null character) to the first location of the array
...
cin.clear(); removes the error flag from cin
and cin.ignore(); ignores the next numbers of spaces.
Since you declared x as a Integer and you write it in first, the console expects that an integer to be read first. if you type abc at first instead you are typing in a string and the console returns an error flag because it expects an integer. That's why your program ends right after that.
If you put cin.clear(); right after cin>>x and type abc the error flag that is been thrown will be ignored and the console continues with cin>>k
I am using the following loop to read numbers from two files until both are exhausted:
int a, b;
while (file1 >> a, file2 >> b, file1 || file2) {
if (file1 && file2) ... // use of both a and b
if (file1) ... // use of a
if (file2) ... // use of b
}
My program works. But is it guaranteed to work by the standard? That is, am I permitted to continue reading from a failed stream or an implementation can choose to throw an exception?
Short answer: Yes, you can attempt to input something from a stream as many times as you want. Even after an attempt to input something from that stream failed. All that will happen is that all attempts to input something after a failed attempt to input something will also fail.
Long answer: operator >> behaves as a formatted input function [istream.formatted.arithmetic]. Formatted input functions construct a local sentry object and only perform input if converting that sentry object to bool results in the value true [istream.formatted.reqmts]. By default (if you did not override this behavior by supplying custom character traits to the stream), an object of type std::sentry will be used. An std::sentry that has been constructed for a stream will evaluate to true only if good() was true [istream::sentry]. good() only returns true if neither failbit nor badbit nor eofbit are set [iostate.flags]/7. If operator >>(int&) attempts to input (due to successful construction and check of the sentry) but fails to do so, it will set the failbit [istream.formatted.arithmetic]/3. If the corresponding flag in the exception mask of the stream is set (it is not set by default), setting the failbit will result in an exception being thrown [iostate.flags]/6 [iostate.flags]/5. Otherwise, the stream will simply be in a failed state and construction of a sentry object will result in false the next time around until you call clear()…
I would consider rewriting this code, for example
do
{
if (int a; file1 >> a)
; // use a
if (int b; file2 >> b)
; // use b
} while (file1 || file2);
Yes, you can do this. Once a stream is in a failed state (failbit), further reads will also fail, but this is what you wanted to happen. These reads will not throw an exception - the failbit will only generate an exception if this is explicitly enabled via the stream's exceptions() method. According to this source, the default is that these exceptions are not enabled:
All streams have goodbit by default (they do not throw exceptions due to error state flags being set).
I was trying to verify if the entered value was an integer with the type id function. I know that the returned value would be i and not integer. I don't know why any entered value returns false and the programs stops. Any help would be appreciated.
The program works fine without the while statement
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int number, factorial;
cout << "Enter a number: ";
cin >> number;
factorial = 1;
while (typeid(number).name() == "i") {
for (int i = number; i >= 1; --i){
factorial *= i;
}
cout << factorial;
}
}
The returned string of the member function name of std::type_info is implementation defined. It's not guaranteed to be "i". If you want to check the type of an object against another type you should do:
typeid(object) == typeid(T)
for any T type. In your example:
typeid(number) == typeid(int)
But the above comparison will always return true because number is declared as int. typeid is usually helpful to inspect the dynamic type of a polymorphic object. In your case number is not polymorphic at all. Therefore you don't need it.
What you seem to be worried about is validation of the input. For that you should consider that if operator>> of std::cin fails the following will happen:
(until C++11)
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(since C++11)
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.
Therefore all you need to do is check the fail bit right after requiring it:
std::cin >> number;
if (std::cin) {
// ...
}
When streams read to an object, they check the format that's being read and parse that format into the object. If the stream cannot correctly parse that data, it sets an error in its error mask. The error mask is used to determine if an I/O operation succeeded or failed. When a stream is put into a boolean context (like in the parameters of an if() or while() loop), it will return true if its error mask is free of any errors.
If your intention is to only use an integer, then I suggest you adopt the pattern of using the stream itself to check if I/O operations succeeded. For example, this is how it will look in your code:
if (std::cin >> number) {
...
}
The formatted extractor operator>>() returns a reference to the stream which will then call its member function explicit operator bool() const to access its stream state and return true or false depending on whether the stream successfully read the contents of the stream into number.
cout << "Enter a positive integer or zero: ";
getline(cin, streamStr);
stringstream(streamStr) >> number;
if (!number) {
cout << "invalid input detected or the input is too big.\n";
return 1;
}
inputs like "%234" or "sdf2334" always fall to 0 , which is false in bool expression, but 0 is still a number.
How to check if the input is really invalid like "%234"??
You need to check the returned value of the operator>>, which is not the same as the value of the variable you're reading into:
if (stringstream(streamStr) >> number) {
...
So what's the returned value, then? If you check the docs, you'll see it's a stream itself. It goes to the operator bool of it (because it's used in an if statement), which in turn returns the validity of the stream, or, IOW, if the last operation succeeded.
If you want to ensure the stream doesn't contain anything besides the number use
if (sstream.rdbuf()->in_avail() > 0) {
// something is still there
And to skip whitespace at the end if you want to allow it:
sstream >> std::ws;
So, all in all...
template<typename T,
// those are optional
enable_if<is_default_constructible<T>::value>::type,
enable_if<is_input_streamable<T>::value>::type
>
optional<T> myRead(string input, bool allowTrailingWs = true) {
stringstream str(input);
T val;
// check parsing
if (!(str >> val))
return none;
// allow whitespace at the end
if (allowTrailingWs)
str >> std::ws;
// check if there's any garbage left
if (str.rdbuf()->in_avail() > 0)
return none;
return val;
}
The code above is just for illustration purposes. Shall you need more advanced parsing, check out Boost.Spirit.
Also, apparently this isn't guaranteed to work every time. Using:
auto inputEnd = ss.tellg();
ss.seekg(0, std::ios::end);
if (inputEnd == ss.tellg()) {
To check if the ss is empty could help fix that.
I don't think you understand how streams work. Allow me to address your misconception:
The stream won't attempt to extract any value into number if the data being evaluated doesn't correspond to formatting requirements of the type. Extraction works by the stream iterating through each character in the character sequence one by one, and testing each character as a viable datum for the type to which the extraction is targeted. If the character is not viable, extraction stops (this is why you are seeing success upon entering something like "2342fdsf"; the stream will keep extracting until it finds an invalid character. "2342" are valid characters for an integer while "f" is not)
If the stream finds an invalid character, nothing further is done to the variable (in this case number). In fact, it is implementation-defined what value an uninitialized variable has if extraction failed to produce any characters. With that in mind, it is potentially dangerous to check the value of the operand to determine if I/O failed. This is where checking the stream state comes in:
std::istringstream iss(streamStr);
if (iss >> number)
{
std::cout << "Extraction produced: " << number << '\n';
}
If the extractions fails, the stream will set the appropriate bits. The stream will then be implicitly converted to a boolean using operator bool() (or operator void*() pre-C++11 where it will subsequently undergo conversion to boolean). The boolean function will check the stream state using !this->fail() (which checks both badbit and failbit) and if the function returns true, the if body will be executed.
If the stream is not in a good state (!this->fail() returns false), that means the extraction failed to produce a value and the if statement body goes unevaluated.
By encasing the extraction in a conditional check, not the value of the thing you tried to extract into.
Assuming number must be a char value, try using the cctype library which is helpful for dealing with strings. It has functions such as
isdigit(Char_Exp) //Returns true if the value is a digit
and
isctrl(Char_Exp) //Returns true if the value is a control character like %(modulus)
Here is a link to a C++ cctype library reference: cctype library reference
To test number I would advise you create a function of type Boolean and so that it tests all possible input errors at once.
What does the istream::getline method return?
I am asking because I have seen that to loop through a file, it should be done like this:
while ( file.getline( char*, int ) )
{
// handle input
}
What is being returned?
It returns a stream so that we can chain the operation.
But when you use an object in a boolean context the compiler looks for an conversion operator that can convert it into a type that can be used in the boolean context.
C++11
In this case stream has explicit operator bool() const. When called it checks the error flags. If either failbit or badbit are set then it returns false otherwise it returns true.
C++03
In this case stream has operator void*() const. As this results in a pointer it can be used in a boolean context. When called it checks the error flags. If either failbit or badbit are set then it returns NULL which is equivalent to FALSE otherwise it returns a pointer to self (or something else valid though you should not use this fact)).
Usage
So you can use a stream in any context that would require a boolean test:
if (stream >> x)
{
}
while(stream)
{
/* do Stuff */
}
Note: It is bad idea to test the stream on the outside and then read/write to it inside the body of the conditional/loop statement. This is because the act of reading may make the stream bad. It is usually better to do the read as part of the test.
while(std::getline(stream, line))
{
// The read worked and line is valid.
}
Look from reference. The istream returned from getline is converted to bool by implicit conversion to check success of operation. That conversion makes usage of if(mystream.getline(a,b)) into shorthand for if(!mystream.getline(a,b).fail()).
It returns the stream itself. The stream can convert (through void*) to bool indicating its state. In this example, your while loop will terminate when the stream's conversion to bool goes "false", which happens when your stream enters an error state. In your code, it's most likely to occur when there was an attempt to read past the end of the file. In short, it'll read as much as there is, and then stop.
The function returns a reference to the stream object itself, which can be used either to chain further read operations:
myStream.getline(...).getline(...);
or, because streams are implicitly convertible to void *s, in a loop or condition:
while (myStream.getline(...)) {
...
}
You can read more about this on the cplusplus.com website:
http://cplusplus.com/reference/iostream/istream/getline/
Everyone has told you what it is, now let me tell you, use the free form version
std::string line;
while(getline(file, line)) // assuming file is an instance of istream
{
//
}
Why this version? It should become immediately apparent - you pass in a std::string rather than some fixed size character buffer!