Cplusplus 简明教程

C++ Exception Handling

异常是在程序执行过程中出现的问题。C++ 异常是对程序运行期间出现的异常情况的响应,例如尝试除以零。

An exception is a problem that arises during the execution of a program. A C++ exception is a response to an exceptional circumstance that arises while a program is running, such as an attempt to divide by zero.

异常提供了一种将控制从程序的一部分转移到另一部分的方法。C++ 异常处理基于三个关键字: try, catch,throw

Exceptions provide a way to transfer control from one part of a program to another. C++ exception handling is built upon three keywords: try, catch, and throw.

  1. throw − A program throws an exception when a problem shows up. This is done using a throw keyword.

  2. catch − A program catches an exception with an exception handler at the place in a program where you want to handle the problem. The catch keyword indicates the catching of an exception.

  3. try − A try block identifies a block of code for which particular exceptions will be activated. It’s followed by one or more catch blocks.

假设某个块会引发异常,方法会使用 trycatch 关键字组合来捕获该异常。try/catch 块放在可能生成异常的代码周围。try/catch 块中的代码被称为受保护的代码,try/catch 的语法如下:

Assuming a block will raise an exception, a method catches an exception using a combination of the try and catch keywords. A try/catch block is placed around the code that might generate an exception. Code within a try/catch block is referred to as protected code, and the syntax for using try/catch as follows −

try {
   // protected code
} catch( ExceptionName e1 ) {
   // catch block
} catch( ExceptionName e2 ) {
   // catch block
} catch( ExceptionName eN ) {
   // catch block
}

可以列出多个 catch 语句来捕获不同类型的异常,以防 try 块在不同的情况下引发多个异常。

You can list down multiple catch statements to catch different type of exceptions in case your try block raises more than one exception in different situations.

Throwing Exceptions

使用 throw 语句可以在代码块内的任何位置抛出异常。throw 语句的操作数确定异常类型,可以是任何表达式,表达式的结果类型确定所抛出异常的类型。

Exceptions can be thrown anywhere within a code block using throw statement. The operand of the throw statement determines a type for the exception and can be any expression and the type of the result of the expression determines the type of exception thrown.

以下是除以零条件发生时抛出异常的示例:

Following is an example of throwing an exception when dividing by zero condition occurs −

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

Catching Exceptions

catch 块在 try 块后捕获任何异常。可以指定要捕获的异常类型,这是由 catch 关键字后括号内出现的异常声明决定的。

The catch block following the try block catches any exception. You can specify what type of exception you want to catch and this is determined by the exception declaration that appears in parentheses following the keyword catch.

try {
   // protected code
} catch( ExceptionName e ) {
  // code to handle ExceptionName exception
}

上面的代码将捕获 ExceptionName 类型的异常。如果要指定一个 catch 块应该处理 try 块中抛出的任何类型的异常,必须在括号中异常声明后面放置一个省略号,…​,如下所示:

Above code will catch an exception of ExceptionName type. If you want to specify that a catch block should handle any type of exception that is thrown in a try block, you must put an ellipsis, …​, between the parentheses enclosing the exception declaration as follows −

try {
   // protected code
} catch(...) {
  // code to handle any exception
}

以下是一个示例,其中抛出了一个除以零异常,我们把它捕获到 catch 块中。

The following is an example, which throws a division by zero exception and we catch it in catch block.

#include <iostream>
using namespace std;

double division(int a, int b) {
   if( b == 0 ) {
      throw "Division by zero condition!";
   }
   return (a/b);
}

int main () {
   int x = 50;
   int y = 0;
   double z = 0;

   try {
      z = division(x, y);
      cout << z << endl;
   } catch (const char* msg) {
     cerr << msg << endl;
   }

   return 0;
}

因为我们引发了类型为 const char 的异常,所以在这个异常被捕获时,我们在 catch 块中必须使用 const char*。如果编译并运行上面的代码,将产生以下结果:

Because we are raising an exception of type const char*, so while catching this exception, we have to use const char* in catch block. If we compile and run above code, this would produce the following result −

Division by zero condition!

C++ Standard Exceptions

C++ 提供了在 <exception> 中定义的一系列标准异常,我们可以在程序中使用这些异常。它们被组织在下面所示的父子类层次结构中:

C++ provides a list of standard exceptions defined in <exception> which we can use in our programs. These are arranged in a parent-child class hierarchy shown below −

cpp exceptions

以下是上述层次结构中提到的每个异常的简要说明:

Here is the small description of each exception mentioned in the above hierarchy −

Sr.No

Exception & Description

1

std::exception An exception and parent class of all the standard C++ exceptions.

2

std::bad_alloc This can be thrown by new.

3

std::bad_cast This can be thrown by dynamic_cast.

4

std::bad_exception This is useful device to handle unexpected exceptions in a C++ program.

5

std::bad_typeid This can be thrown by typeid.

6

std::logic_error An exception that theoretically can be detected by reading the code.

7

std::domain_error This is an exception thrown when a mathematically invalid domain is used.

8

std::invalid_argument This is thrown due to invalid arguments.

9

std::length_error This is thrown when a too big std::string is created.

10

std::out_of_range This can be thrown by the 'at' method, for example a std::vector and std::bitset<>::operator[]().

11

std::runtime_error An exception that theoretically cannot be detected by reading the code.

12

std::overflow_error This is thrown if a mathematical overflow occurs.

13

std::range_error This is occurred when you try to store a value which is out of range.

14

std::underflow_error This is thrown if a mathematical underflow occurs.

Define New Exceptions

您可以通过继承和覆盖 exception 类功能来定义自己的异常。以下示例展示了如何使用 std::exception 类以标准方式实现自己的异常 −

You can define your own exceptions by inheriting and overriding exception class functionality. Following is the example, which shows how you can use std::exception class to implement your own exception in standard way −

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

struct MyException : public exception {
   const char * what () const throw () {
      return "C++ Exception";
   }
};

int main() {
   try {
      throw MyException();
   } catch(MyException& e) {
      std::cout << "MyException caught" << std::endl;
      std::cout << e.what() << std::endl;
   } catch(std::exception& e) {
      //Other errors
   }
}

这将产生以下结果 -

This would produce the following result −

MyException caught
C++ Exception

这里, what() 是异常类提供的一个公共方法,并且它已被所有子异常类覆盖。这会返回异常的起因。

Here, what() is a public method provided by exception class and it has been overridden by all the child exception classes. This returns the cause of an exception.