码迷,mamicode.com
首页 > 其他好文 > 详细

异常处理深度解析

时间:2020-02-12 22:19:09      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:set   int   ret   抛出异常   nat   lib   public   状态   全局对象   

问题:
如果在main函数中抛出异常会发生什么?

技术图片

#include <iostream>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};


int main()
{
    static Test t;

    throw 1;

    return 0;
}

技术图片

 

 不同的编译器打印结果是不同的,但是根据我们编写的程序,不管哪款编译器Test()是肯定会被打印的。差异就在下面打印的东西。使用的该款编译器,当抛出异常时terminate函数被调用了。

如果异常无法被处理,terminate()结束函数会被自动调用
默认情况下,terminate()调用库函数abort()终止程序
abort()函数使得程序执行异常而立即退出
C++支持替换默认的terminate()函数实现

技术图片

#include <iostream>
#include <cstdlib>
#include <exception>

using namespace std;

void my_terminate()
{
    cout << "void my_terminate()" << endl;
    exit(1);
}

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
    }
};


int main()
{
    set_terminate(my_terminate);
    static Test t;

    throw 1;

    return 0;
}

技术图片

exit函数会确保所有的全局对象和静态局部对象全部被正常的析构。如果不调用exit,而是调用abort,又会发生什么?

技术图片

不会调用析构函数,abort是异常终止一个程序,当它异常终止一个程序时,不会调用任何对象的析构函数。

通过本实验,可以得出下面两条结论:

1.在main函数中所扔出的异常如果没有被处理,最终将被一个全局函数处理掉。
2.c++编译器之间存在差异

如果析构函数中抛出异常会发生什么情况?

#include <iostream>
#include <cstdlib>
#include <exception>

using namespace std;

void my_terminate()
{
    cout << "void my_terminate()" << endl;
    exit(1);
}

class Test
{
public:
    Test()
    {
        cout << "Test()" << endl;
    }

    ~Test()
    {
        cout << "~Test()" << endl;
        throw 2;
    }
};


int main()
{
    set_terminate(my_terminate);
    static Test t;

    throw 1;

    return 0;
}

技术图片

 

 你会发现全局函数my_terminate被重复的调用。

已经调用了析构函数,又重复调用析构函数。类似于一个指针指向了堆空间中的一片内存,delete一次就把它释放掉了,如果delete两次就会有问题,造成整个应用程序的不稳定。

当把exit函数换成abort时,又会怎样呢?前面已经说过abort函数是不会调用析构函数的

技术图片

从而就解释了,在terminate函数中,C++默认调用的是abort,而不是exit了。因为abort函数强制的结束当前的应用程序了,它不会去调用析构函数,就是害怕析构函数中又抛出异常

现在可以回答上面提出的问题了,可以在析构函数中扔出异常,但一定不要这样做。这样做会导致很多问题。

原则:在析构函数中一定不要抛出异常,原因如下:

析构函数是用来释放资源的地方,如果抛出异常,有可能导致资源得不到正确的释放
在析构函数里面抛出异常有可能导致全局的结束函数terminate被重复的调用,这是极其可怕的事情,有可能让系统进入极其不稳定的状态。

小结:

技术图片

 

terminate函数 可以在调用abort函数之前,打印一些字符串,弹出一个对话框出来。

异常处理深度解析

标签:set   int   ret   抛出异常   nat   lib   public   状态   全局对象   

原文地址:https://www.cnblogs.com/-glb/p/12301005.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!