I'm just getting started with RAII in C++ and set up a little test case. Either my code is deeply confused, or RAII is not working! (I guess it is the former).
If I run:
#include <exception>
#include <iostream>
class A {
public:
A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; }
~A() { std::cout << "A " << i_ << " destructed" << std::endl; }
private:
int i_;
};
int main(void) {
A a1(1);
A a2(2);
throw std::exception();
return 0;
}
with the exception commented out I get:
A 1 constructed
A 2 constructed
A 2 destructed
A 1 destructed
as expected, but with the exception I get:
A 1 constructed
A 2 constructed
terminate called after throwing an instance of 'std::exception'
what(): std::exception
Aborted
so my objects aren't destructed even though they are going out of scope. Is this not the whole basis for RAII.
Pointers and corrections much appreciated!
Your A objects are not being destroyed because std::terminate is being called.
std::terminate is called when an unhandled exception leaks out of main. If you wrap your code in a try/catch (even if the catch just re-raises) you'll see the behaviour you were expecting.
You are not handling the exception properly, so your application is exiting before the objects go out of scope.
I am going to explain a little more. If an exception "bubbles" up to main the stack is unwound (edit). Even moving the code to a secondary function will not fix this issue. ex:
The above code will not solve the issue. The only way to solve this is to wrap the thrown exception in a try-catch block. This will keep the exception from reaching the main, and stop termination that is happening before the objects go out of scope.
You don't have a handler for your exception. When this happens the standard says that std::terminate is called, which in turn calls abort. See section 14.7 in The C++ Programming Language, 3rd edition.
If an exception escapes main() it is implementation defined weather the stack is unwound.
try
Since the exception is not handled by the time it reaches main(), it results in a call to std::terminate(), you essentially have the equivalent of
Destructors are NOT guaranteed to be called in cases where the program terminates before they go out of scope. For another hole in RAII, consider:
You have an unhanded exception in the main, which means a call to terminate. Try this: