8.1 try / catch / throw
Exceptions let you separate error-handling code from your normal program logic.
Risky code goes inside a try block. If something goes wrong, you throw an exception — an object describing the problem — which immediately halts normal execution and jumps straight to a matching catch block, skipping everything in between.
try {
int a = 10, b = 0;
if (b == 0) throw runtime_error("Divide by zero");
cout << a / b;
} catch (const runtime_error& e) {
cout << "Error: " << e.what();
}
8.2 Standard Exceptions
The <stdexcept> header provides a family of ready-made exception types for common error situations:
std::runtime_errorfor problems detectable only while the program is running.std::out_of_rangefor invalid index access (such asvector::at()).std::invalid_argumentfor bad or out-of-spec function inputs.
All standard exceptions derive from a common std::exception base class, so a single catch (const std::exception& e) block can handle any of them generically through runtime polymorphism using e.what().
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;
vector<int> v = {1, 2, 3};
try {
cout << v.at(10); // throws std::out_of_range
} catch (const out_of_range& e) {
cout << e.what();
}
8.3 Custom Exceptions
For domain-specific business errors, you can define your own exception class by inheriting from std::exception and overriding what(), which returns a human-readable description of the error.
This lets calling code catch your specific error type separately from generic ones, making error handling precise and clean.
#include <exception>
using namespace std;
class InsufficientFunds : public exception {
public:
const char* what() const noexcept override {
return "Not enough balance";
}
};
void withdraw(double balance, double amt) {
if (amt > balance) throw InsufficientFunds();
}