C++ throw(抛出异常)详解

news/2024/7/7 18:31:57

 C++ 异常处理的流程,具体为:

抛出(Throw)--> 检测(Try) --> 捕获(Catch)

异常必须显式地抛出,才能被检测和捕获到;如果没有显式的抛出,即使有异常也检测不到。

在 C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为:

throw exceptionData;

exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型,请看下面的例子:

char str[] = "http://c.biancheng.net";
char *pstr = str;
class Base{};
Base obj;
throw 100;  //int 类型
throw str;  //数组类型
throw pstr;  //指针类型
throw obj;  //对象类型

一个动态数组的例子

C/C++ 规定,数组一旦定义后,它的长度就不能改变了;换句话说,数组容量不能动态地增大或者减小。这样的数组称为静态数组(Static array)。静态数组有时候会给编码代码不便,我们可以通过自定义的 Array 类来实现动态数组(Dynamic array)。所谓动态数组,是指数组容量能够在使用的过程中随时增大或减小。

下面这段代码虽然有点长,但它是一个典型的使用异常的场景,请大家耐心阅读。

#include <iostream>
#include <cstdlib>
using namespace std;

//自定义的异常类型
class OutOfRange{
public:
    OutOfRange(): m_flag(1){ };
    OutOfRange(int len, int index): m_len(len), m_index(index), m_flag(2){ }
public:
    void what() const;  //获取具体的错误信息
private:
    int m_flag;  //不同的flag表示不同的错误
    int m_len;  //当前数组的长度
    int m_index;  //当前使用的数组下标
};

void OutOfRange::what() const {
    if(m_flag == 1){
        cout<<"Error: empty array, no elements to pop."<<endl;
    }else if(m_flag == 2){
        cout<<"Error: out of range( array length "<<m_len<<", access index "<<m_index<<" )"<<endl;
    }else{
        cout<<"Unknown exception."<<endl;
    }
}

//实现动态数组
class Array{
public:
    Array();
    ~Array(){ free(m_p); };
public:
    int operator[](int i) const;  //获取数组元素
    int push(int ele);  //在末尾插入数组元素
    int pop();  //在末尾删除数组元素
    int length() const{ return m_len; };  //获取数组长度
private:
    int m_len;  //数组长度
    int m_capacity;  //当前的内存能容纳多少个元素
    int *m_p;  //内存指针
private:
    static const int m_stepSize = 50;  //每次扩容的步长
};

Array::Array(){
    m_p = (int*)malloc( sizeof(int) * m_stepSize );
    m_capacity = m_stepSize;
    m_len = 0;
}
int Array::operator[](int index) const {
    if( index<0 || index>=m_len ){  //判断是否越界
        throw OutOfRange(m_len, index);  //抛出异常(创建一个匿名对象)
    }

    return *(m_p + index);
}
int Array::push(int ele){
    if(m_len >= m_capacity){  //如果容量不足就扩容
        m_capacity += m_stepSize;
        m_p = (int*)realloc( m_p, sizeof(int) * m_capacity );  //扩容
    }

    *(m_p + m_len) = ele;
    m_len++;
    return m_len-1;
}
int Array::pop(){
    if(m_len == 0){
         throw OutOfRange();  //抛出异常(创建一个匿名对象)
    }

    m_len--;
    return *(m_p + m_len);
}

//打印数组元素
void printArray(Array &arr){
    int len = arr.length();

    //判断数组是否为空
    if(len == 0){
        cout<<"Empty array! No elements to print."<<endl;
        return;
    }

    for(int i=0; i<len; i++){
        if(i == len-1){
            cout<<arr[i]<<endl;
        }else{
            cout<<arr[i]<<", ";
        }
    }
}

int main(){
    Array nums;
    //向数组中添加十个元素
    for(int i=0; i<10; i++){
        nums.push(i);
    }
    printArray(nums);

    //尝试访问第20个元素
    try{
        cout<<nums[20]<<endl;
    }catch(OutOfRange &e){
        e.what();
    }

    //尝试弹出20个元素
    try{
        for(int i=0; i<20; i++){
            nums.pop();
        }
    }catch(OutOfRange &e){
        e.what();
    }

    printArray(nums);

    return 0;
}

运行结果:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Error: out of range( array length 10, access index 20 )
Error: empty array, no elements to pop.
Empty array! No elements to print.

Array 类实现了动态数组,它的主要思路是:在创建对象时预先分配出一定长度的内存(通过 malloc() 分配),内存不够用时就再扩展内存(通过 realloc() 重新分配)。Array 数组只能在尾部一个一个地插入(通过 push() 插入)或删除(通过 pop() 删除)元素。

我们通过重载过的[ ]运算符来访问数组元素,如果下标过小或过大,就会抛出异常(第53行代码);在抛出异常的同时,我们还记录了当前数组的长度和要访问的下标。

在使用 pop() 删除数组元素时,如果当前数组为空,也会抛出错误。


http://lihuaxi.xjx100.cn/news/1886829.html

相关文章

Docker笔记:关于Dockerfile及构建镜像

Dockerfile 的作用 Dockerfile让docker命令变得更简单&#xff0c;是用于构建docker镜像&#xff0c;实现自动化部署 Dockerfile 构建自己的centos镜像 这里有一个应用场景&#xff0c;创建一个自己的centos镜像&#xff0c;这个镜像有我们所需的软件 可以将我们一系列的操作…

ML之FE:数据预处理/特征工程之构造特征—构造交互特征(四则运算/多项式)—将输入特征进行多项式映射,即根据两个特征来构造多项式组合特征的代码实战

ML之FE:数据预处理/特征工程之构造特征—构造交互特征(四则运算/多项式)—将输入特征进行多项式映射,即根据两个特征来构造多项式组合特征的代码实战 目录

docker二 redis单机安装

创建文件夹 mkdir -p /usr/local/redis/data /usr/local/redis/logs /usr/local/redis/conf chmod -R 777 /usr/local/redis/data* chmod -R 777 /usr/local/redis/logs*另一种风格 # 创建 redis 配置存放目录 mkdir -p /home/docker/redis/conf && chmod 777 /home/…

Axure元件的介绍使用与登录界面以及个人简历的绘制

目录 一.Axure元件介绍 1.1.简介 1.2.常见的元件 1.3.元件的操作 二.基本元件的使用 2.1.矩形和圆形 2.2.图片 2.3.文本元件 2.4.热区 2.5.线段元件 三.表单型元件的使用 3.1.文本框 3.2.文本域 3.3.下拉列表 3.4.列表框 3.5.单选按钮 3.6.复选框 四.菜单和表…

QML WebEngineView 全屏和退出

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 在使用浏览器时,我们经常会用到全屏模式,最常见的场景有:观看视频、阅读文章、在线演示等。全屏模式的优点在于,它可以让用户充分地利用有限的屏幕空间,更好地专注于内容本身,从而提供丰富的沉浸式视觉…

磁力计LIS2MDL开发(1)----轮询获取磁力计数据

磁力计LIS2MDL开发.1--轮询获取磁力计数据 概述视频教学样品申请源码下载通信模式速率生成STM32CUBEMX串口配置IIC配置CS设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置设置速率启用偏移消除开启温度补偿设置为连续模式轮询读取数据主程序演示 概述 本文将介绍如何使…

如何基于Python + requests实现发送HTTP请求

这篇文章主要介绍了如何基于Python requests实现发送HTTP请求,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一、在接口自动化测试过程中&#xff0c;存在两种情况&#xff1a; 一种是不需要鉴权的接口&…

【动态规划精选题目】1、斐波那契数列模型

此动态规划系列主要讲解大约10个系列【后续持续更新】 本篇讲解入门级&#xff1a;斐波那契模型&#xff0c;会在讲解题目同时给出AC代码 为什么叫斐波那契数列模型&#xff1f;因为本篇4道题的状态转移方程都跟斐波那契递推方程差不多&#xff0c;但这点不重要&#xff0c;请往…