首页 > 系统相关 >异常---异常安全问题--内存泄漏动图演示

异常---异常安全问题--内存泄漏动图演示

时间:2022-09-28 21:02:15浏览次数:49  
标签:动图 -- 捕获 int 内存 catch 异常 throw

异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的 直接或间接的调用者处理这个错误。

throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。

catch: 在您想要处理问题的地方,通过异常处理程序捕获异常.catch 关键字用于捕获异 常,可以有多个catch进行捕获。

try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。

如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。

 

void func1()
{
    int x, y;
    cin >> x >> y;
    if (y == 0)
    {
        throw "abc";
    }
    cout << x / y;
}


int main()
{
        try
        {
            func1();
        }
        catch (const char* c)
        {
            cout << c<<endl;
        }
}

这是一个普通的捕获异常的代码

一般发生除0错误时,程序会直接报错,终止程序

而为了不让程序直接终止,我们用异常捕获

 

throw:抛异常,可以抛任意类型的异常,抛出去时,会优先抛给进的函数,知道能捕获到它的异常为止,若都没有,则报错。

void func1()
{
    int x, y;
    cin >> x >> y;
    if (y == 0)
    {
        throw "abc";
    }
    cout << x / y;
}

void func2()
{
    try
    {
        func1();
    }
    catch (const char* c)
    {
        cout << c;
    }
}

int main()
{
        try
        {
            func1();
        }
        catch (const char* c)
        {
            cout << c<<endl;
        }
catch(...)
{
cout<<"异常错误";
} return 0; }

这段代码 func2也try保护了func1  所以func1的异常,会优先被func2捕获。而不是被main捕获

catch(...)//这段代码是为了捕获没定义捕获的代码  也是能捕获任意类型的代码。但无法知道捕获过来的到底是哪里的异常。

 

  • 1.在抛出异常对象后,会生成异常对象的拷贝,因为抛出的异常对象,可能是临时对象,所以会生成一个拷贝对象,这个拷贝临时对象在被catch(捕获)后会销毁。
  • 2.可以抛出派生类对象,使用基类捕获,这个在实际非常实用

 

在函数调用链中异常栈展开匹配原则

  • 1.检查throw本身是否在try内,如果是,再召匹配的catch,若没有,则调用到catch的地方处理
  • 2.没有匹配的catch则退出当前函数栈,继续在调用函数栈中召匹配的catch
  • 3.如果到main函数找,依旧没有匹配,则终止程序,所以都需要再最后加上 catch(...) 捕获未知的异常
  • 4.找到匹配catch句子后,会直接catch内的所有句子。

 

异常编码的价值,针对某种错误进行特殊处理。

class A 

 {

 public:

    A(){}

};

    

void foo()

 { throw new A; }

这条代码 正常捕获 为:catch (A * x)

因为  异常是按照类型来捕获的,throw后抛出的是A*类型的异常,因此要按照指针方式进行捕获

 

异常安全问题

int func3(int x, int y)
{
    if (y == 0)
        throw "abc";

    return x / y;
}

int main()
{
    srand(time(0));
    //func2();
    while (1)
    {
        try
        {
            //func1();
            int* p = new int[1024*10];
            p[0] = rand();
            p[1] = rand() % 5;
            cout << func3(p[0], p[1])<<endl;
            delete p;
        }
        catch (const char* c)
        {
            cout << c<<endl;
        }
    }

    return 0;
}

这串代码的大致思路为,创建一个空间 然后在0和1放入随机值。放入func3函数内 如果y为0 会发生除0错误 然后捕获异常

那么原本的思路是 没发生异常  创建->计算->释放   发生异常时 创建->计算->发生异常捕获->释放

但是我们来看下它在任务管理器下发生的变化。

 

 这里我们发现,内存是不断增长的。 

这里可能有人会说,你开辟了空间肯定会涨啊,而且还是死循环。

记住,我确实是开辟了空间,但每次循环里我开辟好空间,计算后,都立刻释放空间。所以正常情况下,我们的内存是增长,然后释放,不断循环。是不会发生一直增长,而不释放的问题的。这就是内存泄漏问题。也就是本次的异常安全问题。

那么接下里。我来演示,正常情况,没有内存泄漏的问题。

 

 可以看到,此次是正常情况下,内存是一直保持在9.7MB 

那为啥会发生内存泄漏问题呢?

原因是  当发生了异常捕获时,那么我们的代码程序是会被throw直接抛出的,然后被catch捕获。那么本该执行delete代码,直接被跳过了,导致内存没有释放。再加上不断的循环,导致越来越多的内存没有释放,最终导致了内存泄漏问题。

也就是说 创建内存后  中间发生了异常,被抛出,程序直接走到了捕获异常那,而不是按照正常的代码逻辑走。 导致了最后没走到delete这段代码,没有成功释放。

 

C++没有垃圾回收记住,资源自己管理,有了异常非常容易导致内存泄漏、死锁等异常安全问题。需要用RAII来处理资源管理问题。

标签:动图,--,捕获,int,内存,catch,异常,throw
From: https://www.cnblogs.com/LonelyMoNan/p/16739533.html

相关文章

  • C++11:智能指针
    C++11中有unique_ptr、shared_ptr与weak_ptr等智能指针(smartpointer),定义在memory中。可以对动态资源进行管理,保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终......
  • java笔记
    **命名规范:**首字母大写,后面每个单词首字母大写(大驼峰)HelloWrold变量名规范:首字母小写,后面每个单词首字母大写(小驼峰)helloWorld方法变量名规范:同变量名 常量:在程序运......
  • C++11:std::bind
    std::bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体,这种机制在回调函数的使用过程中也颇为有用。C++98中,有两个函数bind......
  • 实验1
    Test1#include<iostream>#include<cstring>#include<vector>usingnamespacestd;intmain(){ strings1; strings2{"cplusplus"}; strings3{s2}; strin......
  • protobuf入门教程(五):枚举(enum)、包(package)
    枚举(enum)消息格式当需要定义一个消息类型的时候,可能想为一个字段指定某“预定义值序列”中的一个值,这时候可以通过枚举实现。syntax="proto3";//指定版本信息,不指定会报......
  • 具有50%占空比的奇数整数分频
    参考自《硬件架构的艺术》。思路:产生具有50%占空比的奇数分频时钟,最简单的方式是以期望输出频率的一半(即输出周期的两倍)生成两个正交相位时钟,这两个正交时钟之间有90°的......
  • 流程控制:while循环与for循环
    流程控制:while循环与for循环目录§一、流程控制之while循环1.while条件2.while条件中的关键字3.whileelse语句4.while循环的补充说明§二、流程控制之for循环1.基本使用......
  • for循环
    ......
  • 实验1 类和对象(1)
    #include<iostream>usingstd::cout;usingstd::endl;classPoint{public:Point(intx0=0,inty0=0);Point(constPoint&p);~Point()=default;......
  • NET6 web项目读取 appsettings配置文件
    可以在appsettings中配置数据量连接字符串等数据,便于项目发布后的配置首先,创建ConfigHelper类namespaceTestProject.services{publicclassConfigHelper{......