Throw and Catch Exceptions

beginner c++11

In C++ to raise or throw exceptions the throw keyword is used. To catch exceptions the try and catch keywords are used. The C++ Standard Library provides many basic exception types in the <exception> header. All Standard Library exceptions inherit from std::exception which provides the what() method that returns an explanatory string of why the exception was thrown. Here’s an example of a program that asserts we don’t accidentally divide by 0 and throws a std::invalid_argument if we attempt to:

#include <exception>
#include <iostream>

float strict_divide(float dividend, float divisor) {
  if (divisor == 0.0f) {
    throw std::invalid_argument("Cannot divide by zero");
  }
  return dividend / divisor;
}

int main() {
  try {
    strict_divide(42, 0);
  } catch (const std::invalid_argument& e) {
    std::cout << e.what() << "\n"; 
  }
}
Cannot divide by zero

Catching Different Exception Types

Multiple catch statements can be used to catch exceptions of different types.

#include <exception>
#include <cmath>
#include <iostream>

float strict_divide(float dividend, float divisor) {
  if (!std::isfinite(dividend)) {
    throw std::out_of_range("Dividend isn't finite");
  } else if (!std::isnormal(divisor)) {
    throw std::invalid_argument("Divisor isn't normal");
  }
  return dividend / divisor;
}

int main() {
  try {
    strict_divide(INFINITY, 2);
  } catch (const std::out_of_range& e) {
    std::cout << "Out of Range: " << e.what() << "\n"; 
  } catch (const std::invalid_argument& e) {
    std::cout << "Invalid Argument: " << e.what() << "\n"; 
  }
}
Out of Range: Dividend isn't finite

Or, you can catch std::exception to catch any exception from the standard library.

#include <exception>
#include <cmath>
#include <iostream>

float strict_divide(float dividend, float divisor) {
  if (!std::isfinite(dividend)) {
    throw std::out_of_range("Dividend isn't finite");
  } else if (!std::isnormal(divisor)) {
    throw std::invalid_argument("Divisor isn't normal");
  }
  return dividend / divisor;
}

int main() {
  try {
    strict_divide(42, 0);
  } catch (const std::exception& e) {
    std::cout << e.what() << "\n";
  }
}
Divisor isn't normal

You an also use catch(...) as a “catch anything” statement, ignoring the exception type and message.

#include <exception>
#include <cmath>
#include <iostream>

float strict_divide(float dividend, float divisor) {
  if (!std::isfinite(dividend)) {
    throw std::out_of_range("Dividend isn't finite");
  } else if (!std::isnormal(divisor)) {
    throw std::invalid_argument("Divisor isn't normal");
  }
  return dividend / divisor;
}

int main() {
  try {
    strict_divide(INFINITY, 2);
  } catch (...) {
    std::cout << "Something went wrong\n";
  }
}
Something went wrong

Custom Exception Types

Custom exception types are easy as exceptions are just classes. Exeptions can inherit from Standard Library exceptions as well.

#include <exception>
#include <cmath>
#include <iostream>

class bad_divide : public std::domain_error {
public:
  bad_divide(const char* what, float dividend, float divisor)
  : std::domain_error(what),
    dividend(dividend),
    divisor(divisor) {  
  } 

  float dividend;
  float divisor;
};

float strict_divide(float dividend, float divisor) {
  if (!std::isfinite(dividend)) {
    throw bad_divide("Dividend isn't finite", dividend, divisor);
  } else if (!std::isnormal(divisor)) {
    throw bad_divide("Divisor isn't normal", dividend, divisor);
  }
  return dividend / divisor;
}

int main() {
  try {
    strict_divide(INFINITY, 2);
  } catch (const bad_divide& e) {
    std::cout << e.what() << ": " << e.dividend << " / " <<
      e.divisor << "\n"; 
  }
}
Dividend isn't finite: inf / 2


For more C++ By Example, click here.