• 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++异常机制的实现方式和开销分析

  • 相关阅读:
    尝试了一下Flex
    Flash版的拉格朗日插值程序
    关于CSS属性display:none和visible:hidden的区别
    KMaster知识管理平台功能简介
    企业级知识库系统KMaster推荐
    ie6下的location.href错误
    利用Jquery实现http长连接(LongPoll)
    jQuery高亮插件
    当前知识管理系统的焦点问题以及我的一些解决办法
    知识库如何跟其他业务系统结合
  • 原文地址:https://www.cnblogs.com/kekec/p/2186427.html
Copyright © 2020-2023  润新知