zoukankan      html  css  js  c++  java
  • C++异常深入剖析

    C++异常机制由两部分组成,即抛出端处理端当程序抛出一个异常,控制权不会再回到抛出端

    在抛出端,我们可以抛出一个数或对象,也可以抛出一个指针。

    值得注意的是:被抛出的数、对象或指针都会产生一个副本,这个副本最后被传递给处理端。

    完成抛出动作之后,原来的数、对象或指针会随之被销毁。

    因此要保证此时指针所指向的内存区域不会被回收,否则,抛出的指针将指向一块无效内存区域。

    另外,这个副本是对象的静态类型(不含有动态运行时特性)的拷贝构造函数创建出来的。

    // 最后会在屏幕上打印出"A"
    // 表明在抛出端产生对象副本时,调用的是A的拷贝构造函数
    class A
    {
    public:
    	A(){}
    	A(const A& a)
    	{
    		printf("A\n");
    	}
    	~A(){}
    };
    
    class B : public A
    {
    public:
    	B(){}
    	B(const B& a)
    	{
    		printf("B\n");
    	}
    	~B(){}
    };
    
    void throwFunction()
    {
    	B b;
    	A& a = b;
    	throw a; // 此时会调用A的拷贝构造函数,而不是B的拷贝构造函数
    }
    
    int main(int argc, char* argv[])
    {
    	try{
    		throwFunction();
    	}
    	catch(const A& e)
    	{
    		// ... ...
    	}
    	
    	return 0;
    }
    

    ++++++++++++++++++++++++++++++++++++++++++++

    从以上我们得知,在throw XX时,会进行一次静态拷贝操作。

    为了避免进行第二次拷贝,在处理端应使用引用接受被抛出来的对象,这个过程和函数参数传递类似。

    如果程序没有处理异常,这该异常将由操作系统来接管,在Debug时,会弹出未处理的异常窗口,程序也因此中断运行。

    需要注意的是,抛出端和处理端必须处于同一个模块内,异常才能被捕捉到。

    例如:在try块中调用第三方dll的一个函数,并在其中发生了异常,那么catch块是捕捉不到该异常的。

    关于处理端有五点值得注意:

    (1) 对基本类型,不存在隐式转换

    例如:throw出int类型的数时,catch(double a)捕捉块是捕捉不到该异常的。

    (2) 在抛出对象时,对于多个catch块情况,应先将子类写在前,父类写在后

         因为在匹配时,是从前往后匹配的。

    (3) 当某一catch被匹配上

         若在该catch块中直接throw,将导致该异常对象被重新抛出,此时不会进行拷贝。只是将该异常对象继续传递给下面的catch块

         若在该catch块中throw XX,将会对XX对象进行静态拷贝。并将拷贝后的副本继续传递给下面的catch块。

    (4) catch(const void* a)可以捕捉任何指针类型的异常

    (5) catch(...)可以捕捉任何异常,如果需要用到这个catch块,确保该块放在末尾

    class A
    {
    public:
    	A(){}
    	~A(){}
    };
    
    class B : public A
    {
    public:
    	B(){}
    	~B(){}
    };
    
    void throwFunction()
    {
    	B b;
    	throw b;
    }
    
    int main(int argc, char* argv[])
    {
    	try{
    		throwFunction();
    	}
    	catch(const B& e) // 子类写在父类前面
    	{
    		// ... ...
    	}
    	catch(const A& e)
    	{
    		// ... ...
    	}
    	catch(...)
    	{
    		// ... ...
    	}
    	
    	return 0;
    }
    

    ============================

    Unwinding:现代编译器基本都支持unwinding功能,这使得在一个异常发生时,会将堆栈中的所有对象都析构掉,防止资源泄漏。  

    关于C++异常更多细节请参看:C++异常机制的实现方式和开销分析

  • 相关阅读:
    luoguP2016 战略游戏
    [Usaco2006 Nov]Corn Fields牧场的安排
    [Ahoi2009]self 同类分布
    POJ3208:Apocalypse Someday
    [usaco2010 Oct]Soda Machine
    [Usaco2005 Dec]Scales 天平
    PTA的Python练习题(十九)
    堆叠注入
    PHP序列化与反序列化(三)总结实战
    攻防世界web进阶1-12总结篇
  • 原文地址:https://www.cnblogs.com/kekec/p/2186427.html
Copyright © 2011-2022 走看看