Review: Reading Input in C++

C++ streams will evaluate to a boolean when placed in an if statement or loop condition. The boolean indicates whether the stream can be read from. If the end of the stream is reached, or if an error occurs, the stream will evaluate to false.

C++ input streams also have a feature where operations that extract from the stream, such as

std::cin >> variable
will generally return a reference to the stream, which is why you are allowed to "chain" the >> operator like this: std::cin >> var1 >> var2 >> ...

Together, these features lead to the following idiom: put the code that reads from the stream inside your condition.

while(std::cin >> variable) { ... }
This loop will execute up to the exact point where reading into "variable" fails, and then the loop condition will be false. It doesn't matter whether it fails due to end-of-file or a formatting error or something else. All failures are handled uniformly.

There are many ways to mess up C++ input reading, but if you use the above strategy you will probably be a little less likely to mess it up.

If you need to read line-by-line instead of according to whitespace, you can use std::getline:

std::string line;
while(std::getline(std::cin, line)) { ... }
The full line will be stored in the "line" string variable on each iteration. To process the line stream-style, use a stringstream:
std::string lineStr;
while(std::getline(std::cin, lineStr)) {
  std::stringstream line(lineStr);
  // For example, suppose each line contains two strings and an integer
  std::string s1, s2;
  int n;
  if(line >> s1 >> s2 >> n) { ... }
}

When switching from whitespace-delimited input to line-by-line input, you will need to make sure you're at the start of a line before calling getline. For example, consider this input:

1 2
line1
line2
Suppose the following code is executed:
int one, two;
std::cin >> one >> two;
Then the input stream will be pointing immediately after the 2, but before the newline character on the first line. Therefore, getline will return an empty line if it is called. A simple way to deal with this is to just do an extra getline call, and ignore the result. For example, this code will read the input as expected:
int one, two;
std::cin >> one >> two;
std::string ignore, lineOne, lineTwo;
getline(std::cin, ignore);
getline(std::cin, lineOne);
getline(std::cin, lineTwo);