Program continues even after catching exception?

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
Why my program contiues even after catching..it prints out even the wrong dates/months

#include <iostream>
#include <string>

using namespace std;

class InvalidDay {

    private:
        int day;
        string invalid;
    public:
        InvalidDay(int d_ay);
        ~InvalidDay();
        const string what();


};

InvalidDay::InvalidDay(int d_ay):day(d_ay){

    //1 3 5 7 9 11
    for(int i=1;i<=12;i++){

        if(i==2){
         if (d_ay<1 || d_ay>28)
            invalid="Invalid day entered";
            }
        else if(i%2==0 && i>2){
             if (d_ay<1 || d_ay>30)
                invalid="Invalid day entered";

        }

        else{
             if (d_ay<1 || d_ay>31)
                invalid="Invalid day entered";
            }
    }

}
InvalidDay::~InvalidDay(){}

const string InvalidDay::what(){

    return invalid;
}

string toMonth(int mm){
        string mth;

        switch(mm){

            case 1: mth="Januray";break;
            case 2: mth="February";break;
                    break;
            case 3: mth="March";break;
            case 4: mth="April";break;
            case 5: mth="May";break;
            case 6: mth="June";break;
            case 7: mth="July";break;
            case 8: mth="August";break;
            case 9: mth="September";break;
            case 10: mth="October";break;
            case 11: mth="November";break;
            case 12: mth="December";break;

        }

        return mth;
}

class InvalidMonth {

    private:
        int mnth;
        string invalid;
    public:
        InvalidMonth(int mm);
        ~InvalidMonth();
        const string what();


};

InvalidMonth::InvalidMonth(int mm):mnth(mm){

    if(mm<1 || mm>12)
        invalid="Invalid month entered";


}
InvalidMonth::~InvalidMonth(){}

const string InvalidMonth::what(){

    return invalid;
}

int main(){

    int day=0, mm=0, yr=0;
    string month;


    try{

        cout<<"Please enter birthdate MM/DD/YY: ";
        cin>>mm;
        try{
        month=toMonth(mm);
        cin>>day;
         if(mm<1 || mm>12)throw InvalidMonth(mm);
            }

        catch(InvalidMonth&e){

            cout<<e.what()<<endl;


        }
        cin>>yr;


        if( mm==2 && (day<1 || day>28))throw InvalidDay(day);
        else if( mm%2==0 &&  mm>2 && (day<1 || day>30))throw InvalidDay(day);
        else if(day<1 || day>31)throw InvalidDay(day);


         cout<<"You entered: "<<month<<" "<<day<<" "<<yr<<endl;


        }

    catch(InvalidDay& e){

        cout<<e.what()<<endl;

    }


    return 0;
}
Last edited on
What did you expect to happen after you catch and handle an exception?
stop the execution of wrong values and just print out the error message
Interesting thing, C++ code. It does what you tell it to. If that's what you want to do, it's up to you to do it.
That is what catching exception is all about. If you know how to handle the problem you catch the exception so that the program can continue from there. If you don't know how to handle the problem it's better to just let the exception get thrown further up the call stack, where it might be possible to handle it.
Peter87 wrote:
it's better to just let the exception get thrown further up the call stack, where it might be possible to handle it.
Which is on the main() level rather unlikely.

Why do you throw and catch at the same time? A simple if would the job.

Apart from that I'd guess that you want a single try block and two(?) catch blocks that handles InvalidDay and InvalidMonth (why doesn't something like InvalidYear exists?)
InvalidYear it is optional for my teacher. But if i give two catch blocks, won't the first one to catch error will only execute even if invalid day and invalid months?
But if i give two catch blocks, won't the first one to catch error will only execute even if invalid day and invalid months?

The InvalidDay& catch blocks will only catch InvalidDay exceptions and the InvalidMonth& one just InvalidMonth exceptions.

You could derive your custom exceptions from std::runtime_error (which is actually good practice.) If you do so you could then use a single std::exception& catch block instead.
http://www.cplusplus.com/reference/stdexcept/runtime_error/

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
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;

class FooError : public runtime_error {
public:
    FooError() : runtime_error("Foo error!") {}
};

class BarError : public runtime_error {
public:
    BarError() : runtime_error("Bar error!") {}
};

// not derived from std::error
class UnknownError {
    // can't access its methods later so don't both to declare any!
};

void test(int testCase) {
    try {
        switch(testCase) {
            case 1: throw FooError(); break;
            case 2: throw BarError(); break;
            case 3: throw bad_alloc(); break;  // standard exception for out of memory conditions
            default: throw UnknownError();
        }
    }
    catch(const FooError& e) {
        cerr << "caught FooError : " << e.what() << "\n";
    }
    catch(const BarError& e) {
        cerr << "caught BarError : " << e.what() << "\n";
    }
    catch(const exception& e) {
        cerr << "caught exception : " << e.what() << "\n";
    }
    catch(...) {
        // if you have no idea what's going on you should abort program
        // (ideally after saving any data to file.)
        cerr << "caught unknown exception - aborting!\n";
        exit(0);
    }
}

int main() {
    test(1);
    test(2);
    test(3);
    test(-1);

    return 0;
}


caught FooError : Foo error!
caught BarError : Bar error!
caught exception : std::bad_alloc
caught unknown exception - aborting!


Note that the order of the catch blocks does matter if you are catching the base class of an exception as well. If I reorder test() so std::exception is caught first

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
void test(int testCase) {
    try {
        switch(testCase) {
            case 1: throw FooError(); break;
            case 2: throw BarError(); break;
            case 3: throw bad_alloc(); break; // standard exception for out of memory conditions
            default: throw UnknownError();
        }
    }
    catch(const exception& e) {
        cerr << "caught exception : " << e.what() << "\n";
    }
    catch(const FooError& e) {
        cerr << "caught FooError : " << e.what() << "\n";
    }
    catch(const BarError& e) {
        cerr << "caught BarError : " << e.what() << "\n";
    }
    catch(...) {
        // "catch all" -- must be last!
        // As we have no idea what we're caught, and therefore no idea what the state
        // of the program is, then we need to abort  (ideally after saving any data to file.)
        cerr << "caught unknown exception - aborting!\n";
        exit(0);
    }
}


the output changes to

caught exception : Foo error!
caught exception : Bar error!
caught exception : std::bad_alloc
caught unknown exception - aborting!


That is, all except the unknown exception are handled byt the std::exception catch block.

(GCC did warn me that I was wasting my time with the FooError and BarError catch block as I had the compiler warning level high enough.)

Andy

PS I don't quite see the need for the conditions in your InvalidMonth and InvalidDay constructors (the exceptions are only raised if the month or day is already know to be invalid, using the tests starting on lines 114 (for month) and 126 (for day), yes?)
Last edited on
Thanks, its clearer now...I will give it a try
Topic archived. No new replies allowed.