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<const nested_exception*>(&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;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容