Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent the constructor from creating an object when an exception is thrown

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;
}
like image 876
kmiklas Avatar asked Jun 30 '17 19:06

kmiklas


2 Answers

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.

like image 93
Rakete1111 Avatar answered Oct 20 '22 13:10

Rakete1111


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.

like image 10
Software2 Avatar answered Oct 20 '22 12:10

Software2