异常处理(Exception Handling)

作者:jicanmeng

时间:2017年06月14日


  1. 异常处理的简单例子
  2. 异常处理的流程
  3. catch-all handler

c++语言中,异常处理的使用是有争议的。根据我目前粗浅的学识,还没有看出使用异常处理的必要性。所以对这一部分只是进行了简单的学习。等到需要的时候,再仔细研究。

1. 异常处理的简单例子

异常处理通过三个关键字来实现:try,throw,catch。

首先看一个最简单的例子:

#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    try {
        // Statements that may throw exceptions you want to handle go here
        throw "ab";
    } catch (int x) {
        std::cerr << "We caught an int exception with value: " << x << std::endl;
    } catch (double) {
        std::cerr << "We caught an exception of type double" << std::endl;
    } catch (const std::string &str) {
        std::cerr << "We caught an exception of type std::string" << std::endl;
    }

    std::cout << "Continuing on our merry way\n";

    return 0;
}

运行结果如下:

[jicanmeng@andy tmp]$ ./a.out
                We caught an exception of type double
                Continuing on our merry way
            [jicanmeng@andy tmp]$

几点需要注意的:

  1. trycatch配合使用。我们往往将可能出现问题的代码放在try代码块中,一旦出现异常情况,代码流程就会转到对应的catch代码块中。
  2. 一个try代码块最少要对应一个catch代码块。每一个catch代码块只会捕获一种类型的异常情况。(在上面的例子中,就有三个catch blocks)
  3. catch后面的()中的参数是什么类型的,这个catch代码块只能捕获什么类型的异常。Exceptions of fundamental types can be caught by value, but exceptions of non-fundamental types should be caught by const reference to avoid making an unnecessary copy.(比如上面例子中的第13行)
  4. Just like with functions, if the parameter is not going to be used in the catch block, the variable name can be omitted.(比如上面例子中的第11行)

2. 异常处理的流程

When an exception is raised (using throw), execution of the program immediately jumps to the nearest enclosing try block. If any of the catch handlers attached to the try block handle that type of exception, that handler is executed and the exception is considered handled.

If no appropriate catch handlers exist, execution of the program propagates to the next enclosing try block. If no appropriate catch handlers can be found before the end of the program, the program will fail with an exception error.

例子如下:

#include <iostream>
using namespace std;

void last() // called by third()
{
    std::cout << "Start last\n";
    std::cout << "last throwing int exception\n";
    throw - 1;
    std::cout << "End last\n";
}

void third() // called by second()
{
    std::cout << "Start third\n";
    last();
    std::cout << "End third\n";
}

void second() // called by first()
{
    std::cout << "Start second\n";
    try {
        third();
    } catch (double) {
        std::cerr << "second caught double exception\n";
    }
    std::cout << "End second\n";
}

void first() // called by main()
{
    std::cout << "Start first\n";
    try {
        second();
    } catch (int) {
        std::cerr << "first caught int exception\n";
    } catch (double) {
        cerr << "first caught double exception\n";
    }
    std::cout << "End first\n";
}

int main()
{
    std::cout << "Start main\n";
    try {
        first();
    } catch (int) {
        std::cerr << "main caught int exception\n";
    }
    std::cout << "End main\n";

    return 0;
}

运行结果如下:

[jicanmeng@andy tmp]$ ./a.out
                Start main
                Start first
                Start second
                Start third
                Start last
                last throwing int exception
                first caught int exception
                End first
                End main
            [jicanmeng@andy tmp]$

3. catch-all handler

前面提到,每一个catch代码块只会捕获一种类型的异常情况。但是我们不可能将所有的异常情况都罗列出来。为了解决这个问题,c++提供了一个比较牛逼的catch代码块,catch的参数为...,表示匹配任意类型的异常。举例如下:

#include <iostream>
#include <cmath> // for sqrt() function

using namespace std;

// A modular square root function
double mySqrt(double x)
{
    if (x < 0.0)
        throw "Can not take sqrt of negative number"; // throw exception of type const char*

    return sqrt(x);
}

int main()
{
    std::cout << "Enter a number: ";
    double x;
    std::cin >> x;

    try {
        std::cout << "The sqrt of " << x << " is " << mySqrt(x) << '\n';
    } catch (...) {
        std::cout << "We caught an exception of an undetermined type\n";
    }

    return 0;
}

运行结果如下:

[jicanmeng@andy tmp]$ ./a.out
                Enter a number: -4
                We caught an exception of an undetermined type
            [jicanmeng@andy tmp]$

参考资料

  1. <<C++实用教程>> 电子工业出版社 郑阿奇 主编 丁有和 编著
  2. The C++ Tutorial:
    http://www.learncpp.com/cpp-tutorial/141-the-need-for-exceptions/
  3. misc:
    http://en.cppreference.com/w/cpp/error/exception