3

I am a (somewhat) experienced python programmer trying to migrate to C++. I want to be able to catch invalid user input. For instance, if a variable requires an integer, and the user types a string, I want to catch that error. In python 3, the syntax is:

try:
    #block of code you want to run
except ValueError:
    #Block of code to be run if the user inputs an invalid input

In c++ I read that the syntax is Try, catch. I am trying to do that, but its not working. here is my code in c++:

#include "Calculator.h"
#include <iostream>
#include <exception>

using namespace std;

Calculator::Calculator()
{
}

int Calculator::Calc()
{
    cout << "Enter a number " << endl;
try
{
    cin >> a;
}
catch (logic_error)
{
    cout << "An error has ocurred! You have entered an invalid input!"
}

How can I catch invalid input in c++? Yes, I am using a header file for this class. If you need those contents, let me know. I will continue to search the web and post if I have found an answer!

JohnBobSmith
  • 159
  • 1
  • 3
  • 10
  • 2
    I wouldn't use exceptions to validate user input. I would choose the appropriate conversion method for, say, string to int, and message the user in the event of failed validation, and then reprompt for input. – lurker Oct 31 '13 at 00:41

3 Answers3

5

You will need to #include <limits>

int x;
std::cout << "Enter a number: ";
std::cin >> x;
while(std::cin.fail()) {
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    std::cout << "Bad entry.  Enter a NUMBER: ";
    std::cin >> x;
}
std::cout << "x = " << x << std::endl;

There's a template for you.

ljden
  • 352
  • 1
  • 11
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • I appreciate your answer, a template is what I was looking for! However, why do I need std:: in the code? Im currently getting more errors, here is the updated code at: http://sharetext.org/FMJr – JohnBobSmith Oct 31 '13 at 01:27
  • @JohnBobSmith In your case, you won't, because of the line `using namespace std;`. You can omit every occurrence of `std::` from my answer as long as you're `using namespace std;`, but people will tell you `using namespace std;` is bad practice. – nhgrif Oct 31 '13 at 01:29
  • please see my above edit. Im getting some errors, my code is available at http://sharetext.org/FMJr – JohnBobSmith Oct 31 '13 at 01:33
  • Here is the errors im getting when I try to compile the above code: error: 'numberic_limits' was not declared in this scope... error: expected primary-expression before '>' token... error: no matching function for call to 'max{}' – JohnBobSmith Oct 31 '13 at 01:36
  • Mmm, I think you may need to `#include ` – nhgrif Oct 31 '13 at 01:37
  • Topic solved, adding #include made the code work. One more thing though. why is using namespace std; considered bad practice? – JohnBobSmith Oct 31 '13 at 01:39
  • I don't feel comfortable giving a complete explanation on that as I don't 100% understand it. But a quick Google search will probably turn up some StackOverflow posts where it's been discussed. – nhgrif Oct 31 '13 at 01:41
  • 2
    @JohnBobSmith `using namespace std` is as bad as `from Foo import *` every time you import a module. Eventually you'll get a name clash, call the wrong function, etc. Using `std::` everywhere is often too cumbersome, so a good balance is to `using namespace std;` only inside functions, or `using std::cin; using std::cout` to selectively bring names to the global namespace. – DanielKO Oct 31 '13 at 02:20
4

By default, C++ streams don't throw upon ill-formed input: it isn't exceptional that input is wrong. It is normal. The C++ approach to indicate input failure is to put the stream into failure state, i.e., to set the state flag std::ios_base::failbit. The easiest way to test for wrong input is to use something like

if (in >> value) {
    process(value);
}
else {
    deal_with_input_error(in);
}

Dealing with the input error typically amounts to clearing the stream's state (as long as it is failure mode it won't deal with the actual stream at all) and then to ignore() one or more of the offending characters.

If you really want to get an exception you can set an exception mask:

in.exceptions(std::ios_base::failbit);
try {
    in >> value;
}
catch (std::ios_base::failure const& ex) {
    // deal with the error
}

Whenever in.exceptions() & in.rdstate() is non-zero at the end of any of the members dealing with the state bits or the exception mask is called an exception thrown (i.e. calling in.exception(std::ios_base::failbit) may itself throw an exception). The exception thrown is of type std::ios_base::failure.

I recommend not to use the exception facilities in IOStreams! Input errors are normal and exceptions are for, well, exceptional errors. Using the conversion to bool after having read a value works rather well.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • "Input errors are normal and exceptions are for, well, exceptional errors" -- so I/O failure is an exceptional error or not according to what language you're programming in? Does the English phrase "exceptional error" actually mean anything other than "I hold an incohate disapproval for your use of non-local control flow for a purpose that I consider trivial". And so forth. – Steve Jessop Oct 31 '13 at 00:52
  • It's certainly true that different languages have different opinions on what is worth raising an exception for and what is not. So it's not as odd a statement as it seems. – Kylotan Oct 31 '13 at 00:53
  • @Kylotan: my claim really is that "exceptions are for exceptional errors/circumstances" is a purely circular definition, and does not provide useful guidance to programmers. What's really needed is a far more detailed assessment of the pros and cons of exceptions, which tbh comes with experience rather than simple training and is largely (but not wholly) stylistic. I don't mean to criticise Dietmar for not settling the issue here, merely for implying that it's simple to settle ;-) A C programmer could happily advice C++ programmers to use nothrow new, since allocation failure is "normal". – Steve Jessop Oct 31 '13 at 00:54
  • @SteveJessop: I'm certainly not disapproving the use of exceptions. For example, dealing with running out of memory is a good example of an error which might happen but rarely does. On the other hand, when reading a textual input, there is a fair chance that the input isn't formatted as expected, resulting in an error. I find that dealing with expected errors locally works better than using exceptions. The IOStreams are constructed to make it easy to test for errors without dealing with exceptions. I even described how to use them with exceptions, I'm just recommending against using this. – Dietmar Kühl Oct 31 '13 at 01:02
  • @DietmarKühl: I've never really felt that the likelihood of an error occurring has much to do with how you handle it, other than of course if it affects how you optimize. As you say, you either want to deal with the error locally or you don't. That doesn't depend on whether it happens once a second or once a year, it depends on what component of your program is able to recover. So you might well find that when parsing interactive input you take a different approach from when parsing for example a file. The latter case is less likely to be locally recoverable, so the exceptions are more useful. – Steve Jessop Oct 31 '13 at 01:05
  • +1, though, because an experienced Python programmer should be perfectly able to assess the advice on exception usage for themselves. The questioner no doubt has plenty of practice catching exceptions in different places, since Python produces enough of them :-) – Steve Jessop Oct 31 '13 at 01:11
  • @SteveJessop: Looking at your answer to the question I see you play devil's advocate. This isn't the correct place to discuss this topic, though (nor will we settle this topic). – Dietmar Kühl Oct 31 '13 at 01:11
1

Streams don't throw exceptions by default (they can be configured to do so).

The usual code to read an int is:

int a;
if (std::cin >> a) {
    # OK
} else {
    # error
}

But do be sure that you know what >> actually does here. Specifically, newcomers to C++ are sometimes surprised that it doesn't necessarily read a whole line. So, if you want to validate a whole line of input, or for that matter if you want to retry on failure then you need more code.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699