C++语法系列之9-- 异常处理

1 异常常识:

1)使用throw抛出异常;
2)使用try-catch 语句块捕获异常;
3)catch语句块中,可以使用throw再次抛出当前异常

try {
   g();
} catch (int i) {
   throw;//再次抛出异常 
}

4)可以抛出任意类型的异常。可以是对象,也可以是简单的基础类型。

void process() { 
   if (fail) {
      throw 5;
   }
}

try {
  process():
} catch (int e) {
  return 1;
}

5)也可以抛出C风格的字符串char*

void process() {
   if (fail) {
      throw "failed exception"
   }
}

try {
  process():
} catch (const char* e) {
   std:cerr << e << endl;
}

6)通常应该抛出对象。因为对象的类名称可以传递信息;此外异常可以存储信息,包括用于描述异常的字符串;
7) 以下为匹配所有异常的代码:

try {

} catch (...) {

}

try {

}  catch (const invalid_argument& e) {

} catch (const runtime_error& e) {

} catch (...)  {

}

8)如果程序抛出的异常没有被捕获,程序将终止。可以对main()函数使用try-catch结构以捕获所有没有被捕获的异常;

2 抛出列表

C++允许指定函数或者方法可以抛出的异常。也即抛出列表。
void readFile()
throw(invalid_argument, runtime_error)
{
//code
}
注意:
1)不能仅仅根据抛出列表中的不同异常重载函数;
2)如果函数/方法没有指定抛出列表,那么可以抛出任意异常。
3)如果不想让函数/方法抛出异常,可以使用noexcept

void readFile() noexcept;

4)函数/方法可以抛出 抛出列表之外的异常,但是会导致程序终止;

void readFile() throw(invalid_argument, runtime_error) {
  throw 5;
}

int main() {
    try {
      readFile();
    } catch (int x) {

    }
    return 0;
}

上面的代码会导致程序终止。

5)set_unexcepted
如果出现意料之外的异常,可以使用set_unexcepted更改其行为。
规则如下:
(1)如果处理函数抛出一个新的异常,这个新的异常将会替换掉意料之外的异常,就像新的异常是最初被抛出的一样。
(2)如果新抛出的异常也不在抛出列表中,程序处理如下:
(2.1)如果抛出列表给出了bad_exception,就抛出bad_exception;
(2.2)如果抛出列表没有给出bac_exception,就终止;
set_unexcepted通常用于将意料之外的异常转化为预期的异常;

void myUnexcepted() {
  throw runtime_error("");
}

int main() {
   unexcepted_handler old_handler = set_unexcepted(myUnexcepted);//保存旧的处理函数
try {

} catch (int e) {
  
}  catch (const runtime_error& e) {

}

set_unexcepted(old_handler);//还原
}

由于unexcepted函数作用于整个引用程序而不是这个函数,所以当需要特殊处理程序的代码结束以后,需要还原处理程序。

3 在重写方法中修改抛出列表

在子类中重写虚方法时,如果想让抛出列表比父类中的抛出列表更加严格,可以修改抛出列表。
总结为允许三种情况:
1)删除列表中的异常(注意不是全部删除);
2)添加超类抛出列表中异常的子类;
3)将方法设置为noexcept;
代码例子:

class D {
    
};
class A {
    
};

class B : public A {
    
};

class C : public B {
    
};

class Foo {
public:
    void virtual func() throw (A,D) = 0;
    
};

class Bar: public Foo {
public:
    void virtual func() throw(A);//删除异常D,允许
    void virtual func() throw(A,D,B);//添加A的子类,允许
    void virtual func() throw(B,C);//允许
    //void virtual func() noexcept;//允许
    //void virtual func() throw(B, int);//不允许
    //void virtual func();//全部删除,不允许
};

4 嵌套异常

using namespace std;
class MyException : public exception {
public:
    MyException(const char* msg):mMsg("") {
        mMsg = msg;
    }
    virtual ~MyException() noexcept {}
    virtual const char* what() const noexcept override {
        return mMsg.c_str();
    }
private:
    string mMsg;
};

void doSomething() {
    try {
        throw runtime_error("runtime_error");
    } catch (const runtime_error& e) {
        cout << "catch runtime_error exception : " << e.what() << endl;
        cout <<" throw MyException :" << endl;
throw_with_nested(MyException("Myxception"));
    }
}


int main(int argc, const char * argv[]) {
    // insert code here...
    try {
        doSomething();
    } catch (const MyException& e) {
        const nested_exception *p = dynamic_cast(&e);
        if (p) {
            try {
                p->rethrow_nested();
            } catch (const runtime_error& e) {
                cout << "nested exceprion => " << e.what() << endl;
            }
        }
        
    }
}

执行结果:

catch runtime_error exception : runtime_error
 throw MyException :
nested exceprion => runtime_error

备注:
1)C++高级编程中,讲到嵌套类必须要同时继承混入类std::nested_exception,但是实际测试,不继承也是可以的。
2) 上面使用dynamic_cast将MyException转型,然后获取嵌套类,可以使用rethrow_if_nested简化,代码如下:

int main(int argc, const char * argv[]) {
    // insert code here...
    try {
        doSomething();
    } catch (const MyException& e) {
        
        try {
            std::rethrow_if_nested(e);
        } catch (const runtime_error& e1) {
            cout << "nested exceprion => " << e1.what() << endl;
        }
    }
}

你可能感兴趣的:(C++语法系列之9-- 异常处理)