R
rossum
I have been looking at exceptions as I need to get better at using
them.
I came across an interesting effect, demonstrated below. When I
ctrl-Z the input to throw an ios_base::failure, the first line of
output from cout is lost, even if I clear() and flush(). The only way
I have found to get the first line to appear is to put a newline at
the start. It seems to be ignoring everything up to and including the
first newline.
Investigating further I noticed that a triggering an ios_base::failure
by entering a letter did not have the same effect, nor did a spurious
exception. This led me to a possible diagnosis:
1 cin is waiting for input terminated by a newline.
2 I press ctrl-Z triggering an ios_base::failure.
3 Despite the exception cin is still waiting for its input.
4 I pass some text to cout for output.
5 cout puts the text into the console I/O buffer.
6 cin thinks that the text is input.
7 cin takes text from the buffer until the first newline.
8 Having found a newline cin is satisfied and goes away.
9 Screen output can now operate normally.
I assume that the ability of cin to grab text from cout is because
they share the console I/O buffer. The other triggers did not have a
problem because cin got some input terminated by a newline before the
error was thrown and so was no longer waiting for input.
One thing I have not been able to explain is when I use cerr for
output the same effect happens despite cerr being unbuffered. Maybe
the shared buffer is at a lower level in the system.
I am using Win ME and Dev-C++ 4.9.8.0 with the compiler that comes
with it by default. I do not know if this effect is reproducible on
other systems.
Questions:
1 Is my diagnosis roughly correct?
2 Am I doing something stupid?
3 Is there a standard way to tell cin not to eat the output?
Currently I just add an extra '\n' to the front of the first cout, but
this does mean that the output is different depending on how the file
error was triggered and I would rather avoid that if possible.
rossum
#include <iostream>
#include <stdexcept>
#include <cstdlib>
int main() {
using std::cout;
using std::cin;
const int upper_bound = 10;
const int lower_bound = 2;
cout << "Enter an odd number between " << lower_bound << " and "
<< upper_bound << ": ";
int number = 0;
try {
// Use ctrl-Z to trigger the effect.
// Enter a letter to avoid the effect
if (!(cin >> number))
{ throw std::ios_base::failure("Error reading input stream.");
}
// Use 99 to throw a spurious file error - avoids the effect.
if (number == 99)
{ throw std::ios_base::failure("99 entered."); }
if (number % 2 == 0)
{ throw std::invalid_argument("Number is not odd."); }
if (number > upper_bound)
{ throw std:ut_of_range("Number is too large."); }
if (number < lower_bound)
{ throw std:ut_of_range("Number is too small."); }
} // end try
// File error needs special handling
catch (std::ios_base::failure& ferr) {
// cout.clear(); // No effect
// cout.flush(); // No effect
// cin.clear(); // No effect
cout << "This line does not appear on screen.\n" // \n at end
// cout << "\nThis line does appear on screen." // \n at start
// cout << "This doesn't appear.\nThis does." // \n in middle
// std::cerr << "Output through cerr\n" // Using cerr
<< '\n' << number << ": " << ferr.what() << '\n';
} // end catch
// Other errors do not need special handling
catch (std::exception& err) {
cout << number << ": " << err.what() << '\n';
} // end catch
return EXIT_SUCCESS;
} // end main()
them.
I came across an interesting effect, demonstrated below. When I
ctrl-Z the input to throw an ios_base::failure, the first line of
output from cout is lost, even if I clear() and flush(). The only way
I have found to get the first line to appear is to put a newline at
the start. It seems to be ignoring everything up to and including the
first newline.
Investigating further I noticed that a triggering an ios_base::failure
by entering a letter did not have the same effect, nor did a spurious
exception. This led me to a possible diagnosis:
1 cin is waiting for input terminated by a newline.
2 I press ctrl-Z triggering an ios_base::failure.
3 Despite the exception cin is still waiting for its input.
4 I pass some text to cout for output.
5 cout puts the text into the console I/O buffer.
6 cin thinks that the text is input.
7 cin takes text from the buffer until the first newline.
8 Having found a newline cin is satisfied and goes away.
9 Screen output can now operate normally.
I assume that the ability of cin to grab text from cout is because
they share the console I/O buffer. The other triggers did not have a
problem because cin got some input terminated by a newline before the
error was thrown and so was no longer waiting for input.
One thing I have not been able to explain is when I use cerr for
output the same effect happens despite cerr being unbuffered. Maybe
the shared buffer is at a lower level in the system.
I am using Win ME and Dev-C++ 4.9.8.0 with the compiler that comes
with it by default. I do not know if this effect is reproducible on
other systems.
Questions:
1 Is my diagnosis roughly correct?
2 Am I doing something stupid?
3 Is there a standard way to tell cin not to eat the output?
Currently I just add an extra '\n' to the front of the first cout, but
this does mean that the output is different depending on how the file
error was triggered and I would rather avoid that if possible.
rossum
#include <iostream>
#include <stdexcept>
#include <cstdlib>
int main() {
using std::cout;
using std::cin;
const int upper_bound = 10;
const int lower_bound = 2;
cout << "Enter an odd number between " << lower_bound << " and "
<< upper_bound << ": ";
int number = 0;
try {
// Use ctrl-Z to trigger the effect.
// Enter a letter to avoid the effect
if (!(cin >> number))
{ throw std::ios_base::failure("Error reading input stream.");
}
// Use 99 to throw a spurious file error - avoids the effect.
if (number == 99)
{ throw std::ios_base::failure("99 entered."); }
if (number % 2 == 0)
{ throw std::invalid_argument("Number is not odd."); }
if (number > upper_bound)
{ throw std:ut_of_range("Number is too large."); }
if (number < lower_bound)
{ throw std:ut_of_range("Number is too small."); }
} // end try
// File error needs special handling
catch (std::ios_base::failure& ferr) {
// cout.clear(); // No effect
// cout.flush(); // No effect
// cin.clear(); // No effect
cout << "This line does not appear on screen.\n" // \n at end
// cout << "\nThis line does appear on screen." // \n at start
// cout << "This doesn't appear.\nThis does." // \n in middle
// std::cerr << "Output through cerr\n" // Using cerr
<< '\n' << number << ": " << ferr.what() << '\n';
} // end catch
// Other errors do not need special handling
catch (std::exception& err) {
cout << number << ": " << err.what() << '\n';
} // end catch
return EXIT_SUCCESS;
} // end main()