In C++, exception handling is accompanied by the stack unwinding mechanism — automatic destruction (destructing) of local objects on the call stack that were created before the exception occurred. This phenomenon is important for proper resource release.
Initially, when designing C++, there was no built-in garbage collector, and the task of releasing resources (memory, files, sockets) fell on the programmer. Exception handling was supposed to ensure proper release during code rollbacks due to errors.
Without the mechanism for automatic destruction of objects upon exceptions, resource leaks occur. If resources are not manually released in every catch block, the code becomes complex and unreliable.
C++ implements stack unwinding, where, upon throwing an exception, all objects located on the stack in scope before the throw are destroyed in reverse order of their creation. Their destructors are called automatically.
A classical way to constantly release resources is to use the RAII (Resource Acquisition Is Initialization) pattern: all resources are "wrapped" in objects that release the managed resource upon destruction.
Example code:
#include <iostream> #include <stdexcept> struct FileHandle { FILE* file; FileHandle(const char* path) { file = fopen(path, "r"); if (!file) throw std::runtime_error("Cannot open file"); } ~FileHandle() { if (file) fclose(file); } }; void processFile(const char* path) { FileHandle fh(path); // Will roll back if throw occurs // ... working with the file throw std::runtime_error("Some error"); // fclose will be called automatically }
Key features:
Why can't we just use try-catch and manually call delete or fclose in the catch block to avoid leaks?
Answer:
It’s inconvenient and unreliable: it’s easy to forget to close a resource, especially with multiple exit points or nested resources. Destructors are called even if the exception "flies" through the function; catch is not needed for this.
Will objects on the heap be destroyed if they are not "wrapped" in stack objects during stack unwinding?
Answer:
No. Stack unwinding only calls destructors for objects placed on the stack. To ensure heap objects are destroyed correctly, they must be owned by a stack object (e.g., via smart pointers).
What happens if a destructor throws an exception during stack unwinding?
Answer:
If a second exception is thrown during stack unwinding while destroying any object, the program will terminate with std::terminate(). Never throw exceptions from destructors!
A developer manually closes files and releases memory through catch blocks without using RAII.
Pros:
Cons:
Files and resources are wrapped in RAII wrapper classes. Result: release occurs in destructors, regardless of throw/catch.
Pros:
Cons: