• C++Prime Plus(5)


    85.异常(1)异常处理机制

    异常:运行错误(比如无法打开文件,动态内存申请失败),导致程序无法继续正常运行;

    处理异常的常用方法:

    1.调用stdlib中的abort()函数:输出一个程序异常终止的信息,然后终止程序;
    fig1
    void abort(void) 用于中止程序执行,直接从调用的地方跳出;

    2.利用函数的返回值报告错误;
    fig2
    其中,DBL_MAX是double型的最大值。

    示例:
    fig3
    异常机制
    遇到异常时,将控制权从程序的一个部分转移到另一个部分;

    异常处理的组成部分
    try块:用于标识可能抛出异常的程序块;
    throw抛出异常:程序检测到异常时,跳出当前部分;
    catch捕获异常:处理异常的程序;

    示例:
    fig4
    将对象用作异常类型
    throw可以抛出任何类型的值,catch捕获抛出值的类型(我们可以用不同的类型标识不同的错误)
    我们可以设计一个简单的异常类型:
    fig5
    用异常类型区分不同的错误
    如果程序中用到多个会抛出异常的函数,可以通过抛出的类型确定不同的处理过程:
    fig6
    fig7

    86.异常(2)exception类

    exception类
    对于上一节中,用异常类型区分不同的错误,需要重复写catch,现在我们可以使用C++提供的标准类exception类,用作其他异常类的基类,其中有一个返回字符串的虚函数what(),用于返回出错的原因(利用了C++的多态性)

    fig8
    现在对于不同的异常类型,只需要一个catch就能调用不同的成员(利用了多态性),取决于try内部的操作抛出哪个异常类,但在catch中都是用基类去指向派生类。
    fig9
    bad_alloc异常类
    对于异常类,除了exception基类,C++还有一个bad_alloc异常类:

    • 申请动态变量失败时,早期的C++返回一个空指针,现在的C++则是抛出bad_alloc异常类,bad_alloc从exception派生,提供了what()
      fig10

    87.RTTI(1)

    RTTI:运行阶段类型识别(Runtime Type Identification)

    RTTI用途:
    1.跟踪对象类型;
    2.在继承结构中确定类型转换的安全性;

    支持RTTI的元素
    1.typeid运算符返回一个type_info类类型的值,type_info存储了有关特定类型的信息;
    2.用dynamic_cast检查继承层次中基类指针或引用向派生类转换的合法性;

    typeid运算符和type_info类
    运算符typeid:获取对象的类型信息,是一元运算符
    运算对象:类名 或 结果为对象的表达式
    返回值:type_info对象的引用

    type_info类:有一个成员函数name(),返回类或者对象对应的类名

    示例
    fig11

    88.RTTI(2)

    dynamic_cast运算符:用于检查是否可以安全将基类地址转换成派生类地址。
    fig12
    直接进行类型强制转换,编译器不会检查,会造成后期的内存读写错误,应该使用RTTI,如果返回空指针,对程序的后续行为执行才是安全的。

    89.类型转换运算符

    C语言风格的强制类型转换:(类型名) 表达式

    比如:

    int a=5;
    char* p=(char*) &a;
    int* pi=(int*) p;
    
    • 1
    • 2
    • 3

    C风格的强制类型转换缺点:没有检查或指明所做转换的意义。

    C++严格规范转换限制,使得转换过程更加规范,并设置了4个类型转换运算符:

    • dynamic_cast:用于检查是否可以安全将基类地址转换成派生类地址。
    • const_cast
    • static_cast
    • reinterpret_cast

    const_cast:删除对象的常量性质
    fig13
    输出结果为:
    fig14
    可以发现,其实const修饰的常量并没有被修改(因为常量在内存的不可变区域),const_cast的用途其实是:

    • 当调用了一个形式参数不是const的函数,但实际参数是const的,但是我们确定这个函数不会对参数做修改,因此需要const_cast去除实际参数的const限定,以便函数能够接受这个实际参数。

    static_cast:编译器支持的隐式转换(自动类型转换)
    比如:

    double x=1.998;
    int a;
    a=static_cast<int> x;
    
    • 1
    • 2
    • 3

    可以看出,static_cast是安全的转换,只是会丢失精度;


    C语言自动类型转换出现的场合
    1.赋值或初始化时,如果右边的表达式计算结果类型与左边的变量类型不同:右边值被转换成左边变量类型;
    2.函数参数传递时,实际参数被转换成形式参数的类型;
    3.表达式中的运算数类型不一致,需要遵循转换规则:把精度小的运算数向精度大的运算数转换;


    reinterpret_cast:危险的转换,重新解释地址中的内容
    比如:
    fig15
    reinterpret_cast这种转换看起来是没有意义的(因为两个变量之间没有关联关系),这种转换更多用在输入输出场景(把内存中的一块空间内容完整写入一个文件中)

    C++相比C,增加了类型转换运算符,一是为了让编译器检查类型转换的合理性,二是为了让读代码的程序员看到当前类型转换的意义。

    90.string类

    对于C风格字符串:
    用字符数组存储
    无法用运算符进行操作
    执行字符串操作时需要特别注意空间问题

    C++中专门处理字符串的类,在库string中,用动态数组存储(动态数组可以回顾20.数组的替代品中的vector,注意到另一个替代品array类可以回顾78.类模板(2)非类型参数),必要时会自动扩大空间
    功能:

    • 不同的构造方法
    • 字符串赋值(=)
    • 字符串连接(+)
    • 字符串比较(>, <, >=, <=, ==, !=)
    • 字符串输入输出(>>, <<)
    • 用下标访问字符串的元素

    示例:
    fig16

    91.智能指针

    问题引入
    fig17
    上述函数存在内存泄漏的可能:当抛出异常时,局部变量ps的空间被释放,但ps指向的动态变量没有释放。

    解决方案是使用智能指针;

    智能指针:可以在释放指针本身的空间时候,调用它指向的对象的析构函数,从而析构该指针指向的对象

    智能指针是一个类模板,模板参数是智能指针指向的对象类型。智能指针包含在库memory中。常用的智能指针有3种:

    • auto_ptr:C++98提出
    • unique_ptr:C++11提出
    • shared_ptr:C++11提出

    智能指针示例
    fig18
    3种智能指针的区别:多个指针指向同一个对象时,3种指针有不同的行为

    auto_ptr:在赋值时,会将右边指针的控制权转移给左边指针,右边的指针就失去了控制权(自动指向NULL),这种情况下,对右边指针进行读写操作会出错;

    unique_ptr:明确指出不允许共享,当发生指针赋值时,编译出错;

    shared_ptr:允许多个指针指向同一个对象,析构时,只有最后一个析构的指针会调用对象的析构函数;

    auto_ptr示例
    fig19
    unique_ptr示例
    fig20
    shared_ptr示例
    fig21


    注意到85节中的抛出异常类throw bad_hmean(a, b);语句,bad_hmean是一个类类型;

    91节智能指针中,出现auto_ptr ps (new string("sentence"))auto_ptr (new string("sentence"))这种语句;

    这些类的实例化方式,可以回顾53.对象构造中的内容

    • throw bad_hmean(a, b);中的bad_hmean(a, b)是构造函数的显式调用
    • auto_ptr ps (new string("sentence"))是构造函数的隐式调用(定义对象时自动调用);
    • auto_ptr (new string("sentence"))是构造函数的显式调用

  • 相关阅读:
    Unity3D之动态生成指定数量带间隔的地面
    基于企业知识图谱的企业关联关系挖掘
    设计模式学习笔记--责任链模式
    Redis的四种模式:单机、主从、哨兵、集群
    2021 Adversarial Attack(李宏毅
    你应该了解的10个 Kubernetes 安全上下文设置[译]
    幻兽帕鲁服务器如何安装模组安装
    Spring体系架构
    Redis运维实战之集群中的脑裂
    gslb(global server load balance)技术的一点理解
  • 原文地址:https://blog.csdn.net/qq_40943760/article/details/126283573