9.1 Exceptions and Handling
An exception is an abnormal situation that occurs while a program is running. An exception does not always mean the program must crash; with proper handling, a program can show a message, record the problem, or continue with later logic.
Common Exceptions
Common C++ standard exceptions include:
std::invalid_argument: an argument cannot be accepted, such as converting"abc"withstd::stoi.std::out_of_range: a value or index is outside the allowed range, such asscores.at(10).std::runtime_error: a general runtime failure.std::bad_alloc: dynamic memory allocation failed.std::ios_base::failure: an input/output operation failed when streams are configured to throw.std::logic_error: a broad base class for logic-related errors such as invalid arguments.
if, it often should be. Exceptions are best for failures that may only become clear at runtime.try and catch
Put risky code in try and error handling in catch. Java has finally, and Python has finally; C++ does not have a finally keyword. C++ usually handles cleanup with RAII: local objects clean up in their destructors when the scope ends, whether the scope ends normally or because an exception was thrown.
#include <iostream>
#include <stdexcept>
#include <string>
int main() {
std::string dividend_text;
std::string divisor_text;
try {
std::cout << "Enter dividend: ";
std::getline(std::cin, dividend_text);
int dividend = std::stoi(dividend_text);
std::cout << "Enter divisor: ";
std::getline(std::cin, divisor_text);
int divisor = std::stoi(divisor_text);
if (divisor == 0) {
throw std::invalid_argument("Divisor cannot be 0.");
}
int quotient = dividend / divisor;
std::cout << dividend << " / " << divisor << " = " << quotient << std::endl;
} catch (const std::invalid_argument& error) {
std::cout << "Invalid input: " << error.what() << std::endl;
} catch (const std::out_of_range& error) {
std::cout << "Number is out of range." << std::endl;
}
std::cout << "This calculation is finished." << std::endl;
return 0;
}One possible run:
Enter dividend: 21
Enter divisor: 4
21 / 4 = 5
This calculation is finished.C++ does not have Python's try-else either. Success-only work is usually placed after the risky lines inside try. The flow still stays clear: try attempts, catch handles failure, and object destructors handle cleanup when scope ends.
Catch Specific Exceptions
Do not start by writing an overly broad catch (const std::exception& error). If every exception is caught, real bugs may be swallowed and become harder to find.
try {
int score = std::stoi(line);
} catch (const std::invalid_argument& error) {
std::cout << "Score must be an integer." << std::endl;
}This code catches only std::invalid_argument because the expected failure is "input cannot be converted to an integer."
throw
throw actively throws an exception. It is useful for saying "this input does not satisfy the function's requirements." The problem is detected in the right place, and caller code decides how to handle it.
#include <iostream>
#include <stdexcept>
#include <string>
double normalize_score(int score) {
if (score < 0 || score > 100) {
throw std::invalid_argument("Score must be between 0 and 100.");
}
return score / 100.0;
}
int main() {
std::string text;
try {
std::cout << "Enter score: ";
std::getline(std::cin, text);
int score = std::stoi(text);
double ratio = normalize_score(score);
std::cout << "Score ratio: " << ratio << std::endl;
} catch (const std::invalid_argument& error) {
std::cout << "Invalid input: " << error.what() << std::endl;
}
return 0;
}One possible run:
Enter score: 120
Invalid input: Score must be between 0 and 100.Here, normalize_score() does not print the user message. It only protects its own input rule. The outer caller decides how to explain the problem to the user.