What exactly does "if (!cin)" mean?

I'm having trouble understanding what condition if (!cin) is testing here. I'm sure it comes down to my limited understanding of what is happening with functions like cin and cout. I'm not looking for a deeply technical understanding of it's meaning (not yet, at least). I'm just trying to understand enough so that I can use it effectively. I'm going through a book on c++ right now, and in one of the code examples of a chapter I'm in, I'm seeing this same phrase. Either it wasn't clearly explained earlier in the book, or I missed the explanation. Can someone help me out on this one? Or if you need me to type out one of the code examples I'm looking at, I can do that too. Just let me know.

Thanks!
In C++, stream classes implement operator bool() which allows them to be implicitly converted to a boolean. This boolean indicates whether the streams are in a good or bad state.

http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool
I'm still not exactly sure that I understand what it means for a stream to be in a "bad state".

Here's an example of what I'm looking at below. It's sort of a prototype for a very basic calculator program. What I'm trying to figure out is what the user could do to trigger the (!cin) condition. What input could the user enter in order to cause the input streamto be in a "bad state"???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "std_lib_facilities.h" 

int main() 
{ 
	cout << "Please enter expression (we can handle +, –, *, and /)\n"; 
	cout << "Add an x to end expression (e.g., 1 + 2 * 3x): "; 
	int lval = 0; 
	int rval; 
	cin >> lval; 	// read leftmost operand 
	if (! cin) error(" no first operand"); 
	for (char op; cin >> op; ) // read operator and right-hand operand
	{  						   // repeatedly 
								
		if (op!= 'x') cin >> rval;
		if (! cin) error(" no second operand"); 
		switch(op) 
		{ 
			case '+': 
				lval += rval; // add: lval = lval + rval 
				break;
			case '-': 
				lval -= rval; // subtract: lval = lval – rval 
				break; 
			case '*': 
				lval *= rval; // multiply: lval = lval * rval 
				break; 
			case '/': 
				lval /= rval; // divide: lval = lval / rval 
				break;
			default: 		  // not another operator: print result
				cout << "Result: " << lval << '\n'; 
				keep_window_open(); 
				return 0;
		} 
	} 
	error(" bad expression"); 
}
I could enter "hello" instead of a number, and this would set set std::cin into an error state. All future input operations will automatically fail because of the bad state. When you .clear() the error, "hello" will still be the first thing that gets inputted.

The same would happen if I typed in "3.1415926" because int will not hold that value.

In general, it is a bad idea to use the formatted input operator with std::cin (such as on line 9). It is better to read an entire line of input into a string (which will almost never fail) and then use a std::istringstream to pull things out of that string.
1
2
3
4
5
6
std::string line;
int num;
while((std::cout << "Please enter a positive integer: ") && std::getline(std::cin, line) && (!(std::istringstream{line} >> num) || num < 0))
{
    std::cout << "That is not a positive integer, try again." << std::endl;
}
Try it out - try throwing every bad input you can think of at it.
So the issue is that, when the user tries to cram a value of a particular type into a variable that can't hold that type of value, whatever complicated processes that are going on behind i/o stream, that process, at the risk of sounding crude, gets a little "screwed up", thus putting it in a "bad state", and making it practically unusable???

Nothing is "screwed up". The code behind-the-scenes is smart and knows when it cannot fulfill your request. The way it reacts to this situation is by setting an internal error flag. The way you check that flag is by if(stream) or if(!stream), as well as with more detailed functions such as .good(), .bad(), .fail(), .eof(), etc.

In general, you don't really care what the actual error was, you just want to know that it happened.
LB wrote:
The same would happen if I typed in "3.1415926" because int will not hold that value.

Actually, it would read the integer value 3 and leave ".1415926" to be read by future read operations.
Peter87,

Okay, I was wondering about that part, because I thought that the only thing would happen is that it would be truncated.
Oh, I actually didn't know that. But, at the very least, the next input operation would fail if it expected an integer.
Topic archived. No new replies allowed.