C++异常处理Exception注意事项

1. 异常Exception

抛出异常:

throw some_exception();

捕获异常:

    try {
      f();
      // ...
    } catch (std::exception& e) {
      // ...code that handles the error...
    }

2. 什么时候使用异常

异常通常发生于运行期间,如申请内存失败,类型转换错误, 文件读写失败,或者主动抛出的异常。 一般适用于逻辑不能再执行下去的情况。
C++中异常还是很有用的, 有的时候没有异常很难办。如构造函数中发生异常, 构造函数没办法返回值, 只能抛异常。构造函数抛异常要十分小心, 后文再分析。
使用异常处理能够代替返回错误码的形式,简化代码。

但是, 异常处理也是有代价的,比起没有异常处理的代码, 据估计,有异常处理的代码“大约膨胀5%~10%
执行速度亦大约下降这个数”, 如果没有异常发生,这个数字大约是3%

要不要使用异常,取决于你的程序对执行速度错误响应速度的要求。

  • 如果要求很严格,比如航空领域的飞控系统(人命关天),整个工程中杜绝使用异常处理。
  • 一般来说,非必要不使用异常。
  • 如果你的程序对以上两点要求不是很严格, 可以适当放宽异常使用的限制,毕竟有的时候异常处理能使代码更加简洁。

3. 以引用方式捕获异常

捕获异常的方式和传递函数参数有些类似, 但也有很大不同。 一般有三种方式:值、引用、指针

try {
    cout << "begin" << endl;
    static MyException me("test");
    throw me;
}
catch( MyException e ) {
    cout << "catched exception by value: " << e.what() << endl;
}
catch( MyException* e ) {
    cout << "catched exception by pointer: " << e->what() << endl;
}
catch( MyException& e ){
    cout << "catched exception by reference: " << e.what() << endl;
}

以上代码为例, 传值的方式抛异常, 异常对象会被复制两次, 一次发生在抛出时,一次发生在捕获时;
传指针和传引用差不多, 有人说传指针的话要用确保离开try block时对象还存在, 比如用static。但我试了一下,不用似乎也可以, 可能编译做了一些隐式的拷贝工作。。maybe。。 但在catch block 中要不要delete这个指针是个问题。
一般最好的方式还是传引用, 引用前不必加const, 不必担心临时变量传递给非const引用, 这点和函数传参不同。

4. 构造函数和析构函数

构造函数中使用异常要十分小心, 因为一个构造函数跑出异常, 这个对象没有被完整的构造出来, 则不会调用析构函数对其析构, 这可能造成动态申请和资源不能被释放。

C++只会析构已构造完成的对象

如以下代码就可能造成内存泄露:

struct B{
    B(){ 
    	Foo* pF = new Foo; // 1
    	std::cout << "B()" << std::endl;
    }
    ~B(){ 
    	delete pF;
    	std::cout << "~B()" << std::endl;
    }
};
struct A{
    B b;
    A(){
    	Foo *pF = new Foo; // 2
    	Bar *pB = new Bar; // 3
    	std::cout << "A()" << std::endl; 
	    throw std::exception(); // 4
	   }
    ~A(){
    	delete pF;
    	delete pB;
    	std::cout << "~A()" << std::endl;
    }
};

A和B的析构函数都不会被调用, 但这本身没有问题。 但如果A或B中有分配在堆上的对象,构造函数跑出异常后,则其可能不会被释放。 即使注释掉//4句, 仍可能有问题, 因为//3句本身就可能抛出异常(std::bad_alloc).

析构函数中永远不要抛异常

[Ref]
https://isocpp.org/wiki/faq/exceptions#why-exceptions
“More Effective C++"
https://stackoverflow.com/questions/32323406/what-happens-if-a-constructor-throws-an-exception/32323458

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值