ProgrammingC++ Backend Developer

How does the exception handling system work in C++, and how is it different from other languages? How should one properly design exception handling in industrial applications?

Pass interviews with Hintsage AI assistant

Answer

The exception handling system in C++ is based on the try-catch mechanism and the throw keyword. When an exceptional situation occurs (for example, a resource error, or an invariant violation), an exception is raised inside the try block through the throw operator. The process of searching for a suitable handler (catch) is done by unwinding the stack until the first matching type is found.

Important details:

  • Unlike Java or C#, exceptions in C++ can be of any type (usually a class derived from std::exception).
  • C++ does not have mandatory exception specifications (like checked exceptions in Java); instead, C++11 and later introduced the noexcept specifier.
  • When an exception is thrown, destructors for all objects on the stack between the throw point and the catch point are called — it is vital to support RAII.

Designing:

  • Only throw exceptions for "unexpected" errors; for everything else, use return codes.
  • Catch by constant reference — catch(const std::exception& e).
  • GNU recommends throwing objects that are copied rather than pointers (avoid heap memory).

Code Example:

#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("Process error"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "Caught exception: " << ex.what() << std::endl; } }

Tricky Question

What happens if an exception is thrown from a destructor while another exception is being propagated up the stack?

Answer: The program will terminate abnormally by calling std::terminate() because during exception handling, generating a new exception (double exception) is not allowed, otherwise stack unwinding is disrupted.

Example:

struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("Error in destructor!"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("Error handling"); } int main() { try { func(); } catch (...) { } } // Will terminate via std::terminate()

Examples of real errors due to misunderstanding of the topic


Story

In a large financial application, exceptions were thrown from the destructor of a wrapper class over the database. One of the cornerstone transactions, upon encountering an error, initiated an exception, and during unwind exit, the destructor was called, which also threw an error. The entire application crashed, losing user work. Developers had to urgently replace throw in destructors with logging and proper handling.


Story

A microservice handled exceptions by type: catch(std::exception). One of the threads threw exceptions of user-defined types (not derived from std::exception). Such errors were not caught, leading to unexpected connection drops and memory leaks.


Story

The absence of the noexcept specifier in move methods of containers resulted in the standard library using a slow copy instead of a fast move operation; a significant performance drop was detected only during load testing.