返回首页 C++ 基础教程

C++ 基础

C++ 面向对象

C++ 进阶

异常处理

异常是一个程序执行过程中出现的问题。C++ 异常是对程序运行过程中产生的例外情况作出的响应,比如试图除以零。

异常提供一种方法将程序控制从一个程序的一部分转移到另一部分。C++ 异常处理是建立在三个关键词: 尝试,捕获和抛出之上的。

  • throw: 程序运行出现问题时抛出异常。这是使用一个 throw 关键字实现的。
  • catch: 程序用异常处理器在你想要处理问题的地方捕获异常。catch 关键字显示异常的捕获。
  • try: 一个 try 块标识一个可能会产生异常的代码块。紧随其后的是一个或多个 catch 块。

假设一个代码块将产生一个异常,结合使用 try 和 catch 关键词的方法捕获了一个异常。一个 try / catch 块放置在可能生成一个异常的代码周围。在一个 try / catch 块里面的代码被称为保护代码, try / catch 的语法规则如下:

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

你可以列出多个捕捉语句捕获不同类型的异常, 以防你的 try 代码块在不同的情况下产生了不止一个异常。

抛出异常

异常可以在代码块的任何地方使用抛出语句抛出。把语句的操作数确定类型的异常,可以是任何表达式,表达式的结果的类型决定了类型的异常抛出。

下面是一个例子, 在除以零条件发生时,抛出异常:

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

捕获异常

try 块后的 catch 块可以捕获任何异常。您可以指定你需要捕获何种类型的异常,这是由出现在关键字 catch 后边的括号中的异常声明确定的。

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

上面的代码将捕获到一个 ExceptionName 类型的异常。如果您想要指定一个 catch 块可以应该处理任何在 try 代码中产生的异常, 你必须将一个省略号…放在 catch 后的括号中,异常声明如下:

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

下面是一个例子,这个例子抛出会除零异常, 我们在 catch 块里面捕获它

    #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 *。如果我们编译和运行上面的代码, 这将产生以下结果:

    Division by zero condition!

C++ 标准异常

C++ 在 <exception> 中提供了一系列标准的异常,我们可以用在我们的程序中。这些异常使用父-子分层结构展示如下:

这是对上面提到的层次结构中每个异常的描述:

异常 描述
std::exception 异常和所有标准 C++ 异常的父类
std::bad_alloc 该异常可能会在使用 new 关键字时抛出。
std::bad_cast 该异常可以由 dynamic_cast 抛出。
std::bad_exception 这是一个在 C++ 程序中处理意想不到的异常的有效手段。
std::bad_typeid 该异常可以由 typeid 抛出。
std::logic_error 理论上可以通过阅读代码发现的异常。
std::domain_error 这是一个在数学无效域被使用时抛出的异常。
std::invalid_argument 参数非法时会抛出的异常。
std::length_error 太大的 std::string 被创造时,抛出异常。
std::out_of_range 可以抛出该异常的方法例如 std::vector 和 std::bitset ::operator[] ()。
std::runtime_error 理论上不能通过读代码检测到的异常。
std::overflow_errorr 如果出现数字溢出,则抛出该异常
std::range_error 当你试图存储一个超过范围的值的时候,会抛出该异常。
std::underflow_error 如果出现数学下溢时,抛出该异常。

定义新异常

你可以采用继承及重写异常类来。下面是示例, 显示如何使用 std::exception 类以标准的方式实现自己的异常:

    #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
      }
    }

这将产生如下的结果:

    MyException caught
    C++ 

这里,what() 是一个异常类提供的公共方法,所有子异常类都覆盖了该方法。这将返回一个异常的原因。

上一篇: 文件和流 下一篇: 动态内存