首页 > 编程语言 >标准C++ -- day09

标准C++ -- day09

时间:2023-09-01 19:57:43浏览次数:35  
标签:day09 指向 -- C++ 内存 shared 异常 ptr 指针

一、智能指针
  • 常规指针的缺点:
    • 当一个常规指针离开了作用域时,只有该指针变量本身占用的内存空间(4/8字节)会被释放,而它指向的内存空间不会自动释放,当free、delete、delete[] 语句忘记执行或者无法执行,形成内存泄漏

    • 如何定位内存泄漏、如何预防内存泄漏

  • 智能指针的优点:
    • 智能指针是一个封装了常规指针的类类型对象,并且重载了 * 和-> 运算符,使用起来与常规指针相近

    • 当智能指针离开作用域时,它的析构函数必定执行,从而在析构函数中执行释放常规指针的操作,这样就做到了自动释放的效果,从而避免内存泄漏

    • 智能指针是一个类模板

    • C++STL中提供了四种智能指针:auto_ptr \ share_ptr \ unique_ptr \ weak_ptr

      • 在C++98标准中只有第一个auto_ptr,C++11中只支持后三个,第一个被弃用,使用会产生警告

      • 需要提供头文件 < memory >

      1. auto_ptr
        • 采用独占拥有模式,不能同时有多个auto_ptr指向同一个内存,但是不能完全实现,有时候会指向同一个内存,有隐患

          auto_ptr<int> p1(new int(123));
          auto_ptr<int> p2;    // 可以悬空
          p2 = p1;             //允许,但p1转移所有权给p2,p1可能变成空指针
          *p1;                 // 可能段错误
          
        • 注意:这种独占式不一定成立,p1是否转移给p2不确定

        • 使用格式:

          • auto_ptr< 类型名 > 对象名(new 类型名);

          • 类型 * p = new 类型;
            auto_ptr <类型> 对象名(p);

      2. unique_ptr 独享指针
      • 是 auto_ptr 的升级,完全实现独占式拥有模式,保证同一时间只有一个unique_ptr指向某个内存

      • 通过拷贝构造、赋值操作函数声明为delete来实现不能给另一个unique_ptr对象赋值的效果

        unique_ptr<int> p1(new int);
        unique_ptr<int> p2;
        p2 = p1;    // 报错
        p2 = unique_ptr<int>()
        
      • 可以通过C++ 全局函数 move( ) 来转移内存指向另一个unique_ptr

        • p2 = move(p1);

        • 让p2指向p1原来的内存,p1一定会变成空指针,p2在改变指向前,会先释放自己原来的内存

      1. shared_ptr 共享指针
      • 采用共享的拥有模式,可以允许多个shared_ptr指向相同内存

      • 当一个内存被shared_ptr指向时,内部有一个引用计数器+1

      • 当指向该内存的某个shared_ptr 离开作用域或者改变指向时,引用计数器会-1

      • 当该内存的引用计数器被减为0时,由最后一个离开的shared_ptr在结束前释放该内存

      • 相关成员函数:

        • get( )                    获取指向内存的地址编号

        • use_count( ) 获取引用计数器的值

        • unique( ) 判断指向的内存是否只有一个shared_ptr指向

          • 0 不独占 1 独占
        • reset( ) 放弃对内存的指向 计数+1

      • 全局函数:

        • val2 = move(val1); 移动 val1 的值和使用权给val2

        • swap() 交换两个对象

      • shared_ptr 的循环引用问题:

        • 当两个类(A,B)都有可以指向对方类型的shared_ptr智能指针成员变量(pB,pA)

        • 并且在类外通过shared_ptr 指向new出来的两个类对象(pa指向类A pb指向类B),并且让它们的成员变量 pB pA 指向对方

        • 此时就构成循环引用,导致就算类对象 pa pb 销毁,但它们指向的对象的引用计算也无法减为零(pA pB还在指向)

        • 导致无法释放对象内存,造成内存泄漏

      1. 弱引用指针
      • weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它指向一个由 shared_ptr 管理的对象而不影响该对象的生命周期

      • 将一个 weak_ptr 指向一个 shared_ptr 对象,或者离开时都不会改变该对象的引用计数,只有当最后一个 shared_ptr 离开该对象才会销毁

      • weak_ptr 更像是 shared_ptr 的一个助手,而不是独立的智能指针,因此当 share_ptr 的循环引用产生死锁时,可以把其中一个类的 shared_ptr 成员变量改为 weak_ptr ,即可避免产生死锁

二、异常处理
  • 程序的错误大致分为三种:

    • 语法错误、逻辑错误、运行时错误
  • 运行时错误发生在程序运行期间发生的问题:除零、内存分配失败、非法访问内存、文件不存在、数组越界

  • C++的异常处理机制就是为了解决运行时错误而引用的

  • C语言中运行中错误如果不管,系统会执行默认操作,可能会让程序终止,产生程序崩溃,也可能不终止,但是运行结果不正确。

  • C++提供的异常处理机制,能够捕捉到运行时错误,至少提供了告诉调用者发生了什么事情导致了终止的方式,然后再终止

三、如何抛出异常
  • throw 数据;
    //数据可以是任意类型
    
  • 注意:不要抛出局部变量的地址,因为该地址有可能被释放

  • 抛出的数据不是直接传递给捕获的变量,而是先创建一个匿名对象存储该数据,然后传递该匿名对象

四、如何捕获异常
  • try{
       // 可能会产生异常的代码或函数调用 
    }catch(类型名& 变量名){
        // 如果使用 类型 变量名 方式捕获异常,会对匿名对象再拷贝一次,浪费资源时间,所以一般使用引用获取该匿名函数,可以少一次拷贝
       // 进行异常处理
    }
    
五、异常说明(异常规范)
  • 返回值 函数名(形参列表)[异常说明throw (类型名1,类型名2)]
    {
    
    }
    
    例如:
    void func(void)throw(int,char);
    void func(void)throw() // 表示不抛异常
    
  • 异常说明:相当于该函数的限制或承诺,只抛出说明过异常类型,如果抛出说明外的类型,可以抛出,但是不能接住

  • 但是不同编译器对异常说明的实现不同,有的听从,有的不听从

  • 异常说明是C++98一项功能,C++11后就抛弃了,不建议使用

  • C++11中使用 void func(int x)noexcept 替代

六、标准异常
  • C++已经定义好的异常类,当对应的异常发送时,会自动地抛出定义好的对应的异常类对象

  • std::exception 所有标准异常类的父类,能够捕获所有的标准异常

  • std::bad_alloc new 分配内存失败时抛出的异常

  • std::bad_array_new_length 是它的子类 new 分配的内存数量有误会抛出异常

  • std::bad_cast 该异常可通过 dynamic_cast 抛出

    • 需要 头文件 #include < typeinfo >
  • std::bad_typeid 该异常可以通过 typeid 抛出

    • 当获取具有多态属性的类型指针解引用的类型时,如果不能确定解引用后是哪个类型时,会抛出异常
    Base* b = NULL;
    Base* b1 = new Base;
    Base* b2 = new Son;
    typeid(*b);     // 抛异常
    typeid(*b1);    // Base
    typeid(*b2);    // Son
    
七、自定义异常类
  • 通过设计一个继承了 exception 的异常类,可以个性化地抛出想要的异常

    #define ZZERROR(...) ZZError(__TIME__,__FILE__,__func__,__LINE__,__VA_ARGS__)
    class ZZError : public exception
    {
        string time;
        string file;
        string func;
        size_t line;
        string error;
        public:
            ZZError(const string& time,const string& file,const string& func,size_t line,const string& error):time(time),file(file),func(func),line(line),error(error){}
            ~ZZError(void){}
    
            const string& what(void)
            {
                return error;
            }
    
            friend ostream& operator<<(ostream& os,const ZZError& err)
            {
                return os << "time:" << err.time << " file:" << err.file <<" func:" << err.func << " line:" << err.line << " error:" << err.error;
            }
        };#define ZZERROR(...) ZZError(__TIME__,__FILE__,__func__,__LINE__,__VA_ARGS__)
    
        class ZZError : public exception
        {
            string time;
            string file;
            string func;
            size_t line;
            string error;
        public:
            ZZError(const string& time,const string& file,const string& func,size_t line,const string& error):time(time),file(file),func(func),line(line),error(error){}
            ~ZZError(void){}
    
            const string& what(void)
            {
                return error;
            }
    
            friend ostream& operator<<(ostream& os,const ZZError& err)
            {
                return os << "time:" << err.time << " file:" << err.file <<" func:" << err.func << " line:" << err.line << " error:" << err.error;
            }
        };
    
八、使用异常需要注意的问题
  1. 不要抛出局部变量、对象的地址,而是抛出变量,对象本身

  2. 建议使用引用的方式来捕获异常,减少一次拷贝

  3. 不要在构造函数、析构函数中抛异常

  4. 在捕获异常时,先捕获子类异常,再捕获父类异常

标签:day09,指向,--,C++,内存,shared,异常,ptr,指针
From: https://www.cnblogs.com/bigflyny/p/17672739.html

相关文章

  • ETF2100入门计量经济学
    ETF2100/5910IntroductoryEconometricsAssignment1,Semester2,2023IMPORTANTNOTES:TypeyouranswersusingMicrosoftWordorwriteyouranswersCLEARLY.YoumustsubmitaPDFfiletoMoodle.Otherfileformatsarenotaccepted.Namethefileasfollows:......
  • 线程同步精要
    并发编程有两种基本模型:messagepassing&sharedmemory。线程同步的四项原则:首要原则是最低限度的共享对象,减少需要同步的场合,一个对象能不暴露给别的线程就不要暴露,如果要暴露,优先考虑immutable对象,实在不行才暴露可修改的对象,并用同步措施来充分保护它。其次是使用高级......
  • 线程安全的对象生命期管理
     编写线程安全的类不是难事,用同步原语保护内部状态即可。但是对象的生与死不能由对象自身拥有的mutex保护。racecondition:在即将析构一个对象时,从何而知此刻是否有别的线程正在执行该对象的成员函数?如何保证在执行成员函数期间,对象不会在另一个线程被析构?在调用某个对象的......
  • Jenkins配置徽章
    Jenkins配置徽章1.安装插件系统管理->插件管理->可用插件->EmbeddableBuildStatus->安装2.配置匿名权限3.使用点击:EmbeddableBuildStatus->Markdown->Unprotected复制链接即可.......
  • 三位一体的软件开发成功之道
    在当今数字化时代,产品架构、应用架构和技术架构是构建现代化软件系统的关键要素。它们相互关联,共同影响着软件产品的功能、性能和可扩展性。本文将深入探讨产品架构、应用架构和技术架构之间的关系,并阐明它们在软件开发中的重要性。 一、产品架构产品架构是指在软件产品设计......
  • delphi FireDAC 批量执行命令(批量插入、更新、删除)
    FireDAC批量执行命令(批量插入、更新、删除)代码批量插入procedureTForm1.Button1Click(Sender:TObject);varI:Integer;begin//建立连接FDConnection1.Connected:=True;//开启事务FDConnection1.StartTransaction;try//设置语句FDCommand1.C......
  • 状态模式-22
    概述状态模式(StatePattern)又称状态对象(ObjectsforStates)。当一个对象的内部状态改变时其行为跟着改变。优点:提高可维护性。缺点:增加了类的数量,实现较复杂,不符合“开闭原则”。classContext{privateStatestate;publicsetState(States){state=s;}......
  • 连接未来,驱动创新|腾讯云 CODING DevOps 主题沙龙完美收官
    点击链接了解详情近日,由腾讯云COIDNG主办的“连接未来,驱动创新”主题沙龙在深圳圆满结束。活动现场,来自不同行业的研效专家汇聚腾讯滨海大厦,共同探讨了在不断变革的市场环境之下,组织研发效能提升的前沿策略与实践经验。活动上,Agilean首席顾问、腾讯云TVP吴穹作为研效领域......
  • 《动手学深度学习 Pytorch版》 4.3 多层感知机的简洁实现
    importtorchfromtorchimportnnfromd2limporttorchasd2l模型net=nn.Sequential(nn.Flatten(),nn.Linear(784,256),nn.ReLU(),#与3.7节相比多了一层nn.Linear(256,10))definit_weights(m......
  • 字符编码的相关介绍
    字符编码的介绍前提知识了解字符编辑的介绍字符编辑的发展UTF-8的由来字符编码的应用编码和解码前提知识了解三大核心硬件所有软件都是运行硬件之上的,与运行软件相关的三大核心硬件为cpu、内存、硬盘,我们需要明确三点#1、软件运行前,软件的代码及其相关数据都是存放于......