C++ Exceptions

Sometimes a program runs into a problem it cannot solve on its own, like dividing by zero or asking for data that does not exist. Instead of crashing, C++ lets you catch these problems and respond calmly. This is called exception handling, and it uses three keywords: try, throw, and catch.

try, throw, and catch

Exception handling in C++ is built from three parts that work together. You put risky code inside a try block, signal a problem with throw, and deal with the problem inside a catch block.

KeywordPurpose
tryWraps code that might cause an error
throwSignals that an error has happened
catchHandles the error that was thrown

A first example

In the example below, the program checks a person's age. If the age is below 18, we throw a message. The catch block then receives that message and prints a friendly explanation instead of letting the program crash.

Throwing and catching a value

#include <iostream>
using namespace std;

int main() {
  int age = 15;

  try {
    if (age < 18) {
      throw age;
    }
    cout << "Access granted.";
  }
  catch (int myAge) {
    cout << "Access denied. Age is only " << myAge;
  }
  return 0;
}

Using the standard exception type

You can throw any type of value, but it is cleaner to throw an exception object. The <stdexcept> header gives you ready-made types such as runtime_error. You catch them by reference and read the message with the what() function.

Throwing a runtime_error

#include <iostream>
#include <stdexcept>
using namespace std;

double divide(double a, double b) {
  if (b == 0) {
    throw runtime_error("Cannot divide by zero");
  }
  return a / b;
}

int main() {
  try {
    cout << divide(10, 0);
  }
  catch (const runtime_error& e) {
    cout << "Error: " << e.what();
  }
  return 0;
}
Note: Catch exceptions by const reference (const runtime_error& e). This avoids making an unnecessary copy and is the standard, recommended style in modern C++.

Catching any exception

If you are not sure which type might be thrown, you can use catch(...) with three dots. It acts as a safety net that catches every kind of exception. It is handy as a last resort, but try to catch specific types first so you can give better error messages.

A catch-all handler

#include <iostream>
using namespace std;

int main() {
  try {
    throw "Something unexpected happened";
  }
  catch (...) {
    cout << "An error occurred, but we handled it safely.";
  }
  return 0;
}
  • Wrap risky code in a try block.
  • Use throw to report a problem.
  • Use catch to handle the problem and keep the program running.
  • Prefer standard exception types and read messages with what().

Exercise: C++ Exceptions

What is the purpose of a try block in C++?