When a constructor throws an exception, how can I prevent the object from being created?
In the example below, I create a Month() class, for which legal values of the int month_
property are in the range of 1 to 12. I instantiate December, or dec
, with integer value 13. The exception is thrown, as it should be, but the object is still created. The destructor is then called.
How do I abort creation of a class instance upon a thrown exception?
OUTPUT
-- Month() constructor called for value: 2
-- Month() constructor called for value: 6
-- Month() constructor called for value: 13
EXCEPTION: Month out of range
2
6
13
-- ~Month() destructor called.
-- ~Month() destructor called.
-- ~Month() destructor called.
Press any key to exit
Minimal, complete, and verifiable example
#include <iostream>
#include <string>
class Month {
public:
Month(int month) {
std::cout << "-- Month() constructor called for value: " << month << std::endl;
try {
// if ((month < 0) || month > 12) throw 100; Good eye, Nat!
if ((month < 1) || month > 12) throw 100;
} catch(int e) {
if (e == 100) std::cout << "EXCEPTION: Month out of range" << std::endl;
}
month_ = month;
}
~Month() {
std::cout << "-- ~Month() destructor called." << std::endl;
}
int getMonth()const { return month_; }
private:
int month_;
};
int makeMonths() {
Month feb(2), jun(6), dec(13);
std::cout << feb.getMonth() << std::endl;
std::cout << jun.getMonth() << std::endl;
std::cout << dec.getMonth() << std::endl;
return 0;
}
int main() {
makeMonths();
std::cout << "Press any key to exit"; std::cin.get();
return 0;
}
How do I abort creation of a class instance upon a thrown exception?
Well, you throw an exception in the constructor. But there's a catch: Don't catch it!
If you catch it, it would be like the exception never happened. You caught it, so it doesn't go up the call stack anymore. So the object is created, because as far as anyone is concerned, the constructor did not throw an exception.
If you remove the catch
clause from the constructor, you'll probably get something like:
-- Month() constructor called for value: 2
-- Month() constructor called for value: 6
-- Month() constructor called for value: 13
terminate called after throwing an instance of 'int'
[1] 28844 abort (core dumped) ./main
Here, the constructor threw an exception, and it went up the call stack outside of the constructor this time because no one caught it in the constructor. It then goes to makeMonths
, where it is also not caught, and then to main
, where it is also not caught, and so the program terminates abnormally.
By default, throwing an exception in a constructor should prevent the destructor from ever being called. However, you are catching the exception and handling it.
You could throw a new exception inside your catch that can then be seen outside this scope so that the destructor is not called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With