Exception handling

Hi

I'm trying to get a grip on exception handling and am going nowhere.
I picked a simple beginning error that I've had when coding:
Getting an integer input from user. The error would be a non-integer (float/character). I tried my own code (try, throw, catch) and couldn't stop getting some weird behaviour.

Could anyone help me get a real feel for this?
I have a list of error codes but no idea what the meanings mean.
I'd like not just one way of doing it but a few for an idea of some language complexities. Maybe some basic and a bit advanced.. not too advanced, I'll be back for those in awhile ;)
If you post the code, you would get more help. The question is vague.

http://www.cplusplus.com/forum/articles/40071/#msg218019
Okay. This is the code I've got now. It's not what I started with but I've tried a few different versions and none of them work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <stdexcept> 

using namespace std;

int main()
{
    int a;
    while (cout << "Enter an integer: ") {
        try {
            if (cin >> a)
                cout << a << '\n';
                else throw runtime_error("Error!");
        } catch (runtime_error err) {
            std::cout << err.what()
                 << "\nTry Again?  Enter y or n\n";
            char c;
            cin >> c;
            if (!std::cin || c == 'n')
                break;
        }
    }
    return 0;
}


The problem here (I think) is that (when I enter a float e.g. 1.5) cin >> c doesn't wait for input, execution carries on to the next line. Possibly cin needs to be flushed first because of the incorrect data type? How would this be done?
Last edited on
It is incorrect usage of exceptions: if you know how to handle problem locally, you should do so. Exceptions are needed to notify parent code about problem and to let it handle the problem themselves.

Example:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <fstream>
#include <iostream>
#include <string>
#include <stdexcept>

struct io_error : std::runtime_error
{
    using runtime_error::runtime_error;
};

struct file_not_found : io_error
{
    using io_error::io_error;
};

struct incorrect_format : io_error
{
    using io_error::io_error;
};

struct foo
{
    int i;
    int a;
    int x;
};

foo read_from_file(std::string filename)
{
    std::ifstream infile(filename);
    if(!infile.is_open())
        throw file_not_found(filename);
    foo result;
    if(! (infile >> result.i >> result.a >> result.x))
        throw incorrect_format("invalid file format");
    return result;
}

int main()
{
    std::string name;
    std::cin >> name;
    try {
        foo bar = read_from_file(name);
        std::cout << bar.i << '\n';
    } catch (const file_not_found& e){
        std::cerr << "File not found: " << e.what() << "\nCreating new file...\n";
        foo bar {1, 2, 3};
        std::ofstream out(name);
        out << bar.i << ' ' << bar.a << ' ' << bar.x << '\n';
        std::cout << bar.i << '\n';
    } catch (const incorrect_format& e){
        std::cerr << e.what();
    }
}
Here read_from_file does not know what to do in case of problem. Should it return some default object? Should it fail? Should it create new file? Should it do that everytime?
That function can be used in many places, each of which migh require own problem handling. So best way for read_from_file to handle problem is to delegate it to the calling function.
In my example, it will create a new default file if file does not exist, but will do nothing if file is corrupt.


In your case you should just use condition statements to handle incorrect input.
Last edited on
Okay. Condition statements. How?
Anything trying to input a non-int into an int causes weird issues. Generally what I get is the cin failing every time after this (i.e. cin doesn't stop program flow to receive input but keeps passing the same non-int (when in a loop as above).
In case you don't know what I mean, this code causes the same problem

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

using namespace std;

int main()
{
    int a;
    while (cout << "Enter an integer: ") {
        if (cin >> a, cout << a << endl);
        else (cout << "Error: not an integer");
    }
    return 0;
}
Ok, let me explain some things:
(when I enter a float e.g. 1.5) cin >> c doesn't wait for input
When you read an int, extraction operator reads stuff up until first non-digit, and leaves rest for further input operations.
In your case it reads 1 and leaves .5 for further reads. Next read tries to read . as int and fails, setting stream in failed state and leaves offending input in stream.
You need to handle that incorrect input and reset stream state afterwards:

Something like that will work:
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
#include <iostream>
#include <limits>

int main()
{
    while (true) {
        std::cout << "Enter an integer: ";
        int a;
        //Reject non-space delimited input like 44asd
        if (std::cin >> a && isspace(std::cin.peek())) {
            std::cout << a << '\n';
        } else {
            std::cout << "Incorrect input!\nTry Again?  Enter y or n\n";
            std::cin.clear(); //Reset stream state
            //clear offending input:
            while(!isspace(std::cin.peek()))
                std::cin.get();
            //Alternative: clear whole line
            //std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            char c;
            std::cin >> c;
            if (!std::cin || c == 'n') break;
        }
    }
}

Okay.
Why use isspace?

1
2
        if (std::cin >> a && isspace(std::cin.peek())) {
            std::cout << a << '\n';
Because you want to catch stuff like 1.5 and 44asd and threat them as invalid input. In correctly entered data there is always a whitespace character (a space, tab or newline) after input (POSIX says that files should be terminated with a newline, so it holds true for last input as well).
oic

If a space is entered though e.g. 1.5 1.5, this isn't handled, is it the while missing it?

1
2
            while(!isspace(std::cin.peek()))
                std::cin.get();
This is two inputs entered as one line (whitespace delimited input is native for C++). If you want that everything on line to be threated as single input you need different algorithm — different requirements = different code.
Oh. Okay.
Thanks, I think you've covered it all.
Much appreciated
Topic archived. No new replies allowed.