C语言里面的错误处理使用不同的数值表示不同类型的错误,传统的错误处理方法存在很大缺点:其表达能力有限;状态编码与错误码难以形成统一标准,例如同样用途的程序库,不同的开发商可能采用不同的错误编码方案来标识不同类型错误;有些函数没有返回值(例如构造函数和析构函数)等等。

C++异常处理机制将异常类型化,显然一个类型比一个数字包含的信息量大得多。C++保证,如果一个异常在抛出点没有得到处理,那么它将一直被抛向上层调用者,直至main函数,指导找到一个类型匹配的异常处理器,否则调用terminate结束程序。可以看出:异常处理机制实际上是一种运行时通知机制

任何类型都可以当做异常类型,异常仅仅通过类型而不是通过值来匹配的。所以下面这段代码是OK的,只是我们一般不使用基本数据类型的对象作为异常。

try{
 if(..) throw 0;
}
catch(int){
 cerr << "exception!" << endl;
}

try{
 if(..) throw "error msg";
}
catch(const char *){
 cerr << "exception!" << endl;
}

在使用异常处理机制的环境,应当使用函数异常说明,如示例所示:

double Devide(double x, double y) throw(DevidedByZero); // 只抛出这类异常

bool func1(const char *p) throw(T1, T2, T3); // 可能抛出三种异常

void func2() throw(); // 不抛出任何异常

void func3(); // 可能抛出任何异常,也可能不抛出异常


下面我就写一个工程上使用异常处理的demo做为文章的结束,比较简陋但已经展示了异常处理的用法。

/*
 * Copyright (c) 2016 xxxx Inc, All rights reserved.
 * Created: 2016-02-01
 */

#include <iostream>
#include <exception>
#include <execinfo.h>
#include <stdlib.h>

#define DEFAULT_PROGRAM_NAME "TEST-PROGRAM"

class TestException : public std::exception{
public:
  TestException() {}
  virtual ~TestException() {}

  TestException(
    const char *errMsg ):
    m_program( DEFAULT_PROGRAM_NAME ),
    m_errmsg( errMsg )
  {
    getStackTrace();
  }

  /* Obtain a backtrace and print it to stdout. */
  void getStackTrace(void)
  {
    void *array[10];
    size_t size;
    char **strings;
    size_t i;

    size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);

    for(i = 0; i < size; i++)
    {
      m_callStack += strings[i];
      m_callStack.push_back('\n');
    }
    free(strings);
  }

  virtual const char *what() { return m_errmsg.c_str(); }
  virtual const char *where() { return m_callStack.c_str(); }

protected:
  std::string m_program;
  std::string m_errmsg;
  std::string m_callStack;

}; 

void func(void)
{
  if(true)
    throw TestException("throw an exception in func.");
}

int main(int argc, char *argv[])
{
  try{
    func();
  }
  catch(TestException &e){
    std::cout << "catch TestException, " << e.what() << std::endl;
    std::cout << e.where() << std::endl;
  }

  return 0;
}