C++异常

#include <iostream>
using namespace std;
int divide(int a,int b){
    if(b)
        return a/b;
    else
        throw "b can't zero.";
}
int main(){
    int a,b;
    cin >> a >> b;
    try{
        cout << divide(a,b) << endl;
    }
    catch(const char *s){
        cout << s << endl;
    }
    return 0;
}

  如果异常没有catch住的话,最终会导致程序调用abort(),异常终止。

  如果异常不是本函数产生的话,可以再将异常抛出。在这个例子中print可以没有catch。

#include <iostream>
using namespace std;
int divide(int a,int b){
    if(b)
        return a/b;
    else
        throw "b can't zero.";
}
void print(int result)
{
try{
    cout << result << endl;
    }
catch(const char *s){
    throw;
    }
}
int main(){
    int a,b;
    cin >> a >> b;
try{
    print(divide(a,b));
}
catch(const char *s){
    cout << s << endl;
}
    return 0;
}

  引发异常时,编译器总会自动创建一个临时拷贝,即使异常catch块中指定的是引用。因为f()异常,导致桟解退,a已经被析构了。

class problem{//...};
void f()
{
    if(//...){
        problem a;
        thow a;
    }
    //...
}
int main()
{
    try{
        f();
    }
    catch(problem &b){
        //.....
    }
    return 0;
}

  可以利用类的关系来接异常

class bad_1{};
class bad_2:public bad_1{};
class bad_3:public bad_2{};
void f()
{
    if()
        throw bad_1();
    else if()
        throw bad_2();
    else if()
        throw bad_3();
    //....
}
int main(){
    try{
        f();
    }
    catch(bad_3 &a){

    }
    catch(bad_2 &b){

    }
    catch(bad_3 &c){

    }
}

  如果不知道异常的类型,可以用cathc(...){}来接住任何异常。

异常规范和C++

void f() throw(int,double){}

  这是C++98的新特性,但是C++11却摒弃了,不过还是支持它。表明f()可能会抛出int和double的异常,并保证该函数不会抛出任何其他类型的异常。让编译器添加执行运行阶段检查的代码,检查是否违背了异常规范。如果在运行时,函数抛出了一个没有被列在它的异常规范中的异常时(并且函数中所抛出的异常,没有在该函数内部处理)则系统调用C++标准库中定义的函数unexpected()。仅当函数中所抛出的异常,没有在该函数内部处理,而是逆调用链回溯寻找匹配的catch子句的时候,异常规范才起作用。如果异常规范形式为throw(),则表示不得抛出任何异常。

void f() noexcept;//表明f()不会引发任何异常

桟解退(unwinding the stack)

exception类

异常的基类

//c++11
class exception {
public:
  exception () noexcept;
  exception (const exception&) noexcept;
  exception& operator= (const exception&) noexcept;
  virtual ~exception();
  virtual const char* what() const noexcept;
}

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

下表是对上面层次结构中出现的每个异常的说明:

异常异常 描述
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_error 当发生数学上溢时,会抛出该异常。
std::range_error 当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error 当发生数学下溢时,会抛出该异常。

异常终止函数设置

当异常没有接住时,程序自动调用terminate函数,而terminate默认调用abort函数,可以通过set_terminate来修改这个默认值。

typedef void (*terminate_handler)();
terminate_handler set_terminate(terminate_handler f) noexcept//c++11
void terminater() noexcept;

  如果在异常规范中引发了规范中没有的异常,程序将调用unexpected函数,unexpected默认调用terminate,并最总导致abort函数的调用。可以通过set_unexpected来修改这个默认值。

typedef void (*unexpected_handler)();
unexpected_handler set_unexpected(unexpected_handler f) noexcept//c++11
void set_unexpected() noexcept;
posted @ 2018-04-11 18:25  h_hg  阅读(353)  评论(0编辑  收藏  举报