No, throwing an exception is the best way to signal an error during object construction. (Since there's no return value, there's no other way, other than constructing a headless object, which is bad style in C++.)
From the man himself, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions
(If you are working in a project where exceptions aren't allowed, then you have to make the constructor infallible, and move any logic that could fail into a factory function that has the possibility of returning an error.)
Re: "But my destructor was not called"
Indeed.
In C++ the lifetime of an object is said to begin when the constructor runs to completion. And it ends right when the destructor is called. If the ctor throws, then the dtor is not called.
(But dtors of any member variable objects, whose ctors already ran to completion before this ctor ran, are called.)
You should consult the standard, or a good textbook for more details, esp. related to what happens when inheritance is involved. As a general rule of thumb, destructors are called in the reverse order of construction.
Your question about why "~B" was not called in your specific code, it's because you do not catch the exception in main. If you change your code so that main catches the exception, then "~B()" will be called. But, when an exception is thrown which has no catch, the implementation is free to terminate the program without calling destructors or destroying statically initialized objects.
Reference in C++11 standard (emphasis mine):
15.5.1 The std::terminate() function [except.terminate]
1
In some situations exception handling must be abandoned for less subtle error handling techniques.
...
2
In such cases, std::terminate() is called (18.8.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.
As a side note, generally speaking with gcc and clang, ~B
will be called anyways in your example program, while with MSVC, ~B
will not be called. Exception handling is complex and the standard allows that compiler writers can experiment with and choose what implementation that they think is best in this regard, but they cannot choose to give undefined behavior.
If it's really important for your program that the destructors are called even in this case, then you should make sure to catch exceptions in main
so that your code will be portable (work the same on all conforming compilers). For example:
int main() {
try {
A a;
} catch (...) {}
}
This way, compilers like MSVC will be obligated to call the destructor of B
before exiting.