Error & Exception Handling: try-catch, std::exception, noexcept & RAII Stack Unwinding
1Concept
C++ exception handling uses try, catch, and throw. When an exception is thrown, the runtime performs Stack Unwinding: all local stack variables in active frames are destroyed in reverse order, ensuring RAII destructors release resources. noexcept marks functions that guarantee never to throw, enabling compiler optimizations.
2Architecture Diagram
[try Block] ──► throw std::runtime_error("...")
│
▼ [Stack Unwinding Initiated]
[Destroy Local Frame 2 (Call RAII Destructors)]
[Destroy Local Frame 1 (Call RAII Destructors)]
│
▼
[catch (const std::exception& e)] ──► Handle error cleanly & Log e.what()3Code Example
Stage 0 Language Foundations
#include <iostream>
#include <stdexcept>
#include <string>
class DatabaseConnection {
public:
DatabaseConnection() { std::cout << " -> DB Connection opened.\n"; }
~DatabaseConnection() { std::cout << " -> DB Connection closed via RAII cleanup.\n"; }
};
void execute_query(int query_id) {
DatabaseConnection conn; // Stack-allocated RAII object
if (query_id < 0) {
throw std::invalid_argument("Query ID cannot be negative!");
}
std::cout << " -> Query " << query_id << " executed successfully.\n";
}
int main() {
std::cout << "=== C++ Exception Handling & Stack Unwinding ===\n";
try {
std::cout << "Testing valid query:\n";
execute_query(101);
std::cout << "\nTesting invalid query (will throw):\n";
execute_query(-5);
}
catch (const std::invalid_argument& ex) {
std::cerr << "[Caught Exception] " << ex.what() << "\n";
}
catch (const std::exception& ex) {
std::cerr << "[General Exception] " << ex.what() << "\n";
}
std::cout << "Program recovered and continuing normally.\n";
return 0;
}4Expected Output
=== C++ Exception Handling & Stack Unwinding === Testing valid query: -> DB Connection opened. -> Query 101 executed successfully. -> DB Connection closed via RAII cleanup. Testing invalid query (will throw): -> DB Connection opened. -> DB Connection closed via RAII cleanup. [Caught Exception] Query ID cannot be negative! Program recovered and continuing normally.
5Key Takeaways
- ✓Always catch exceptions by const reference (const std::exception& e) to avoid object slicing.
- ✓RAII destructors execute automatically during stack unwinding even when exceptions throw.
- ✓Mark move constructors and destructors noexcept for optimal vector resizing performance.