Error Handling in C++: try, catch and Modern Approaches

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Error Handling in C++: from try/catch to RAII and noexcept



Program reliability directly depends on how it responds to unexpected situations. In C++, the main mechanism for this is exceptions. In this article, we will analyze the classic try/catch/throw construct, as well as consider alternative and modern approaches: RAII, noexcept, and error handling without exceptions.



1. Basic Mechanism: try, catch, throw



An exception is an object that is "thrown" (throw) when an error occurs. The program can catch it (catch) and perform corrective actions without completely stopping execution.



Syntax

#include <iostream>#include <stdexcept>

double divide(double a, double b) { if (b == 0.0) { throw std::runtime_error("Division by zero!"); } return a / b;}

int main() { try { double result = divide(10.0, 0.0); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0;}


Rules of Operation

  • throw — creates a copy of the object and transfers control to the handler.
  • try — a block of code where exceptions may occur.
  • catch — catches an exception by type. Multiple catch blocks can be specified.
  • If an exception is not caught, std::terminate() is called.


Catching by Base Class

All standard exceptions inherit from std::exception. Therefore, you can write a universal handler:

try {    // code} catch (const std::exception& e) {    std::cerr << "Standard error: " << e.what() << std::endl;} catch (...) {    std::cerr << "Unknown exception" << std::endl;}

The catch (...) block catches absolutely all exceptions, but without access to the object.



2. Exceptions in Constructors and Destructors



Constructors

If a constructor throws an exception, the object is considered not created, and its destructor is not called. This is important for resource management. Example:

class Resource {public:    Resource() {        std::cout << "Resource allocated" << std::endl;        throw std::runtime_error("Initialization error");    }    ~Resource() {        std::cout << "Resource freed" << std::endl;    }};

int main() { try { Resource r; } catch (...) { std::cout << "Exception caught" << std::endl; } // Resource destructor will NOT be called! return 0;}


Destructors

Throwing exceptions from a destructor is bad practice. If a destructor is called during stack unwinding and it throws a new exception, the program will terminate abnormally. Always write destructors as noexcept (they are by default).



3. RAII — Automatic Resource Management

The RAII (Resource Acquisition Is Initialization) idiom is the key to safe code. A resource (memory, file, mutex) is acquired in the constructor and released in the destructor. If an exception occurs, the destructors of all created objects are called automatically (stack unwinding), and resources are freed.



Example with a smart pointer std::unique_ptr:

#include <memory>#include <iostream>

void process() { auto ptr = std::make_unique<int>(42); // If an exception occurs here, // unique_ptr will automatically delete the memory throw std::runtime_error("Error in proc

Blogs

Book Recommendations