| the book has those variables outside the while loop | 
This is a common thing in many books that follow an older C-style design.
Back when we were all wee laddies (or not yet born!) C required all variables to be declared before any statements. So:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | void my_func()
{
  int    x;
  char * s;
  float  f;
  for (x = 0;  x < 10;  x++)
  {
    s = ...;
  }
  f = ...;
}
 | 
{,} to create a local lexical context and keep stuff together, but few people ever did...)
It appears your book is following that way of thinking. It’s not... 
wrong, per se, but it isn’t the way modern C++ (and C!) should be written.
The thing to remember is that 
the compiler can do it better than you can. Hard to accept, but true. Let the compiler do its job.
| If the line below replaces the internal buffer with the string, shouldn't it internally just reset the bit flags as well? [...] | 
You’d think so, but that’s not how the class was designed to function. I’m pretty sure there’s an actual reason for that. I don’t know what it is. It has never caused me any difficulties.
| It looks like they are suggesting terminating the program when the cin stream is bad. Is this what is done? | 
Maybe. Depends on your program.
| Or if the cin was trivial in only getting the user name and you never relied on it again, can you bypass using the cin again (and use a default name) and continue your program? | 
Sure. However you design your program to work.
| Or does a bad cin indicate something more sinister? | 
Remember, standard input is just another input stream. A special one, yes, but a character file none-the-less.
Remember, 
all streams can have:
  • an end
  • access/privilege errors
  • data your program does not like
For standard input, the user can terminate it by pressing 
Ctrl+Z,
Enter (Windows) or 
Ctrl+D (*nixen), or by simply redirecting a normal file from disk to it, or a piped file from another utility to it, etc.
If the file simply does not contain data you like that is something the program should handle.
Part of the problem is that code like this is exampled almost everywhere, and it is almost always WRONG. (With capital everything.)
(The same holds true for 
scanf(), but I’ll leave that rant for another day.)
There are two issues:
  • Text files, and standard input specifically, are 
line based data.
  • C++ streams allow you to goober the state of the stream more or less permanently.
Use 
getline() to obtain a line of input from 
cin (or your 
ifstream), then use an 
istringstream to parse it.
Likewise, use an 
ostringstream to format data, then send the resulting string through 
cout (or your 
ofstream object).
This is because 
cin, 
cout, and 
cerr are 
global, shared resources. If you jack its state, some other part of your program may very well malfunction when attempting to use it.
Hence, use a local, temporary stringstream to do things like set persistent formatting preferences and simply pass the string data through the standard streams unmodified.
This, of course, requires a little more care when programming, and tends to make writing short examples harder in how-to books, websites, etc, so you see a lot of
| 12
 3
 4
 5
 
 |   cout << hex << STUFF;
  ...
  /* end of program */
 | 
Instead of the more correct:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | std::ostream & operator << ( std::ostream & outs, Stuff stuff )
{
  std::ostringstream oss;
  oss << hex << stuff.value;
  return outs << oss.str();
}
...
int main()
{
  Stuff my_stuff;
  ...
  std::cout << my_stuff << "\n";
}
 | 
Meh. Enough ranting. :O)
| seeplus wrote: | 
|---|
| You can even do this: 
 
 | 12
 3
 
 | // Attempt to read a line and print the values we got
if (double low, high; ss >> low >> high)
    std::cout << std::setw(8) << low << std::setw(8) << high << "\n";
 | 
 | 
I still don’t know how I feel about that. In one way it is definitely welcome — the ability to declare a variable in-line and use it is nice...
But it comes at the cost of obscure syntax. I mean, I know what it means and can read it just fine, but it still takes a second to process, where the following is just so much more straight-forward:
| 12
 3
 
 |   double low, high;       // ah, variables! one named "low" and another "high"
  if (ss >> low >> high)  // hey, an "if" statement. Easy peasy!
    ...
 | 
If scope of those two variables is an issue, a pair of curly braces 
{,
} fixes that easily enough and remains just as readable.
The only time I can imagine such a construct being actually useful is in old & crufty macro tricks where we currently have to use a 
do..
while loop or a GCC compiler extension.
But then, I think I tend to write fairly clean code...
IDK.