C++异常处理详解 看这一篇就够了

这篇具有很好参考价值的文章主要介绍了C++异常处理详解 看这一篇就够了。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在程序运行的过程中,我们不可能保证我们的程序百分百不出现异常和错误,那么出现异常时该怎么报错,让我们知道是哪个地方错误了呢?
C++中就提供了异常处理的机制。

异常处理的主要关键字

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
  • try:try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块(至少要跟一个)。

当被try的括号包围的代码块(我们可称之为保护代码)出现异常时,就会抛出异常,catch块的代码就会捕获异常并执行catch包围的代码块。因为异常也可以有不同的种类,所以我们可以在try后面跟着多个catch块,捕获不同的异常,如下:

try
{
   // 保护代码
}
catch( ExceptionName1 e1 )//第一种异常
{
   // catch 块
}
catch( ExceptionName2 e2 )//第二种异常
{
   // catch 块
}
catch( ExceptionName3 eN )//第三种异常
{
   // catch 块
}

抛出异常

使用 throw 语句可以在代码块中的任何地方抛出异常。
throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。
如下:

#include <iostream>
using namespace std;
double division(double a, double b)
{
    if (b == 0)
    {
        throw "出现了除数为0的错误";//throw关键字抛出错误
    }
    return (a/ b);
}
int main()
{
    cout << division(1, 0);
}

如果我们在Visual Studio2019中运行这段代码,那么它就会在throw的地方停止程序并报错,
c++ exception,《从C语言过渡到C++和虚幻引擎中的C++编程》系列教程,c++,开发语言,虚幻,c语言,游戏引擎

可以看到,我们抛出的是一串字符串,所以编译器报错的信息说异常类型是char(其实是const char*,但它简写了)。
实际我们编程的时候,我们肯定不希望编译器就只给我说异常类型是char*就完了。我们还希望把它打印出来,让我们看得到"出现了除数为0的错误",这就需要捕获异常。

捕获异常

我们把会抛出异常的代码放到try代码块里面,再用catch关键字捕获异常。如下:

#include <iostream>
using namespace std;
double division(double a, double b)
{
    try
    {
        if (b == 0)
        {
            throw "出现了除数为0的错误";//throw关键字抛出错误类型 const char*
        }
    }
    catch (const char* error_string)//捕获const char*类型的错误
    {
        cout << error_string << endl;//打印它
    }
    return (a / b);
}
int main()
{
    cout << division(1, 0);
}

在Visual Studio2019中运行它,就会看到:
输出结果:

出现了除数为0的错误
inf

c++ exception,《从C语言过渡到C++和虚幻引擎中的C++编程》系列教程,c++,开发语言,虚幻,c语言,游戏引擎
可见,有了try和catch后,程序不会在遇到错误时崩溃终止,而是会处理它,然后继续运行。
所以这个程序依然能输出计算结果inf(无限大),但是在此之前也打印了报错信息。
总之,利用异常处理机制,我们就可以在程序运行时处理异常,大大减少程序崩溃的概率。

你在生活中经常遇到软件闪退的问题,十有八九没有做好异常处理。

C++标准库自带的异常类型

C++ 提供了一系列标准的异常,定义在 头文件exception 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:
c++ exception,《从C语言过渡到C++和虚幻引擎中的C++编程》系列教程,c++,开发语言,虚幻,c语言,游戏引擎
下表是对上面层次结构中出现的每个异常的说明:

  • std::exception 该异常是所有标准 C++ 异常的父类。 std::bad_alloc 该异常可以通过 new 抛出。
  • std::bad_cast 该异常可以通过 dynamic_cast 抛出。 std::bad_typeid 该异常可以通过 typeid
    抛出。 std::bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用。
  • std::logic_error 理论上可以通过读取代码来检测到的异常。
  • std::domain_error 当使用了一个无效的数学域时,会抛出该异常。
  • std::invalid_argument 当使用了无效的参数时,会抛出该异常。
  • std::length_error 当创建了太长的std::string 时,会抛出该异常。
  • std::out_of_range 该异常可以通过方法抛出,例如 std::vector 和std::bitset<>::operator。
  • std::runtime_error 理论上不可以通过读取代码来检测到的异常。
  • std::overflow_error 当发生数学上溢时,会抛出该异常。
  • std::range_error 当尝试存储超出范围的值时,会抛出该异常。
  • std::underflow_error 当发生数学下溢时,会抛出该异常。

异常规格说明

throw关键字

异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。 可以在函数的声明中列出这个函数可能抛掷的所有异常类型。例如:

void fun() throw(A,B,C,D);

throw后面的括号内,必须写出会抛出的异常的类型,如果括号里面是空的,说明这个函数不会抛出任何异常。
如果你不声明throw(A,B,C,D),那么编译器就会认为这个函数什么异常都可能会抛出。
异常规范声明可以让编译器知道可能会抛出的异常有哪些,就可以提升编译速度和给编译器更多的优化空间,让你的代码性能更高,也可以让其他程序员了解你这段代码可能会产生的异常,提高代码可读性。

noexcept关键字

在C++11中新增了noexcept关键字以表示这个函数不会抛出某种异常。并且可以阻止异常的传播。

无条件的noexcept关键字

当我们声明的noexcept关键字无条件时,表示这个函数中所的所有代码都不会产生异常,如下:

void fun() noexcept; //C++11
void fun() noexcept(); //也可以写成这样,等价的
void fun() noexcept(...); //也可以写成这样,等价的
void fun() noexcept(true); //也可以写成这样,等价的
有条件的noexcept关键字
void fun(Type& x, Type& y) noexcept(noexcept(noexcept(fun1()),noexcept(fun2()));
//表示fun函数内会调用到的fun1函数和fun2函数都不会抛出异常,但不保证其他代码不会抛出异常
什么时候我们需要noexcept关键字?

使用noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。然而,并不是加上noexcept就能提高效率。
以下情形鼓励使用noexcept:

  • 移动构造函数(move constructor)
  • 移动分配函数(move assignment)
  • 析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。下面代码可以检测编译器是否给析构函数加上关键字noexcept。
  • 叶子函数(Leaf Function)。叶子函数是指在函数内部不分配栈空间,也不调用其它函数,也不存储非易失性寄存器,也不处理异常。
    最后强调一句,在不是以上情况或者没把握的情况下,不要轻易使用noexception。

定义新的异常类型

只有C++标准库自带的异常类型肯定是不够用的,我们实际工作中还需要根据项目需求定义新的异常类型。
在C++中,异常类型都有个共同的基类(父类)——exception 类,我们定义新的异常时最好继承exception 类,exception 类在头文件exception中定义,你需要定义新的异常时需要#include它,如下:

#include <iostream>
#include <exception>
using namespace std;
class DivisionZeroException :public exception//基于exception类定义新的异常类型除以0导致的异常类
{
public:
    //这里重载了父类的虚函数what()
    //throw ()的括号里面没有东西,这表示这个函数不会抛出任何异常
    //const 是常量的关键字,常量在定义后无法被修改
    const char* what() const throw ()
    {
        return "出现了除以0的错误\n";
    }
};
double division(double a, double b)
{
    try
    {
        if (b == 0)
        {
            DivisionZeroException e;
            throw e;//throw关键字抛出错误类型DivisionZeroException
        }
    }
    catch (DivisionZeroException e)//捕获const char*类型的错误
    {
        cout<<e.what();//打印什么异常了
    }
    return (a / b);
}
int main()
{
    cout << division(1, 0);
}

输出结果:

出现了除数为0的错误
inf

异常类也可以被继承,所以在实际软件开发中,我们可以把异常分为几个大类,然后继承出许多小类来处理千变万化的异常类型。文章来源地址https://www.toymoban.com/news/detail-629123.html

到了这里,关于C++异常处理详解 看这一篇就够了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C→C++】打开C++世界的大门(C++基础入门,看这一篇就够了)

    这篇文章开始,我们正式进入C++的学习。 什么是C++ C语言是结构化和模块化的语言,适合处理较小规模的程序。 对于复杂的问题,规模较大的程序,需要高度的抽象和建模,C语言则不合适。 为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object oriented programming:面向对

    2024年02月07日
    浏览(23)
  • 【C++】Clang-Format:代码自动格式化(看这一篇就够了)

    Clang-format格式化C代码 官方参考文档: Clang-Format Style Options — Clang 16.0.0git documentation (llvm.org) ClangFormat — Clang 16.0.0git documentation (llvm.org) 1.引言安装 1.1引言 进入公司之后,会发现每个公司都有自己的代码规范,针对于其中的代码格式规范,手动去控制十分繁琐,因此这里提供

    2024年02月04日
    浏览(57)
  • getchar函数详解看这一篇就够了-C语言(函数功能、使用、返回值)

    首先要明确getchar的功能是:从计算机终端(一般是键盘)输入一个字符,其值就是输入得到的字符。 目录 getchar函数简介 getchar函数执行过程详解(配图)  getchar用法示例 解释一下:while ((ch=getchar()) != \\\'EOF\\\') 函数原型:int getchar(void);                                 返回

    2024年02月07日
    浏览(27)
  • 【Nginx】入门看这一篇就够啦,nginx 简介、安装、工作原理、工作方式、详解配置文件

    目录 1、nginx 简介 2、nginx的工作原理 3、nginx 工作方式 4、nginx 安装 命令行安装 卸载命令 从源码构建 查看版本 测试启动 5、详解nginx配置文件 第一部分:全局块 第二部分:events块 第三部分:http 6、hosts 文件简介 nginx [engine x] 是 HTTP 和反向代理服务器、邮件代理服务器和通

    2024年02月19日
    浏览(27)
  • memcmp函数详解 看这一篇就够了-C语言(函数讲解、函数实现、使用用法举例、作用、自己实现函数 )

    memcmp()函数用于:比较两个内存块 函数声明:int memcmp ( const void * ptr1, const void * ptr2, size_t num ); 参数: ptr1:指向内存块的指针。 ptr2:指向内存块的指针。 数字:要比较的字节数。 返回值: 0: 在两个内存块中不匹配的第一个字节在  ptr1  中的值低于 在 ptr2  中的值(如果计

    2023年04月09日
    浏览(24)
  • strstr函数详解 看这一篇就够了-C语言(函数讲解、函数实现、使用用法举例、作用、自己实现函数 )

     strstr()函数用于:查找子字符串 目录 函数介绍 用法示例 函数讲解 实现函数  事例展示 函数声明:char *strstr(const char *str1, const char *str2) 头  文  件:#include string.h 返  回  值: 返回值为char * 类型( 返回指向  str1  中第一次出现的  str2  的指针);如果  str2  不是 

    2024年02月13日
    浏览(18)
  • CSS基础——看这一篇就够了

    目录 一、CSS简介 1.CSS是什么? 2.CSS的作用 3.CSS的构成 二、CSS选择器 1.基础选择器 (1).标签选择器 (2)类选择器 (3)标签选择器 (4) 通配符选择器 2.复合选择器 (1)后代选择器(包含选择器) (2)子选择器 (3)并集选择器 (4)伪类选择器  三、基本属性 1.字体属性

    2024年02月09日
    浏览(25)
  • 精通线程池,看这一篇就够了

    当我们运用多线程技术处理任务时,需要不断通过new的方式创建线程,这样频繁创建和销毁线程,会造成cpu消耗过多。那么有没有什么办法 避免频繁创建线程 呢? 当然有,和我们以前学习过多连接池技术类似,线程池通过提前创建好线程保存在线程池中, 在任务要执行时取

    2023年04月17日
    浏览(33)
  • SourceTree使用看这一篇就够了

     你梦想有一天成为git大师,然而面对复杂的git命令,你感觉TMD这我能记得住吗?你曾经羡慕从命令行敲git命令,才会更加炫酷,然而时间一长,TMD命令我有忘了。那么今天我介绍的这款工具会让你从git命令中解救出来,这就是git可视化工具SourcTree。 事实上Git的功能十分强大

    2024年02月08日
    浏览(26)
  • 还不会二分查找?看这一篇就够了

    二分查找分为整数二分和浮点数二分,一般所说的二分查找都是指整数二分。 满足单调性的数组一定可以使用二分查找,但可以使用二分查找的数组不一定需要满足单调性。 不妨假设我们找到了条件 C 1 C_1 C 1 ​ ,它和它的 对立条件 C 2 C_2 C 2 ​ 能够将数组 a a a 一分为二,

    2024年01月19日
    浏览(19)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包