C++ 异常处理 入门

2023-11-15

C++ 异常处理 入门

异常:程序执行期间,可检测到的不正常情况。

例如:0作除数;数组下标越界;打开不存在的文件;远程机器连接超时;malloc失败等等。

程序的两种状态:

正常状态和异常状态,发生不正常情况后,进入异常状态,从当前函数开始,按调用链的相反次序,查找处理该异

常的程序片断。

1.throw 表达式

语义:用表达式的值生成一个对象(异常对象),程序进入异常状态。

Terminate函数,终止程序的执行。

2.try-catch语句

try{

    包含可能抛出异常的语句;

}catch(类型名 [形参名]){

}catch(类型名 [形参名]){

}

例子程序:

#include <iostream>
#include <math.h>

using namespace std;

double sqrt_delta(double d){
 if(d < 0)
  throw 1;
 return sqrt(d);
}

double delta(double a, double b, double c){
 double d = b * b - 4 * a * c;
 return sqrt_delta(d);
}

void main()
{
 double a, b, c;
 cout << "please input a, b, c" << endl;
 cin >> a >> b >> c;

 while(true){
  try{
   double d = delta(a, b, c);
   cout << "x1: " << (d - b) / (2 * a);
   cout << endl;
   cout << "x2: " << -(b + d) / (2 * a);
   cout << endl;
   break;
  }catch(int){
   cout << "delta < 0, please reenter a, b, c.";
   cin >> a >> b >> c;
  }
 }
}

3.重新抛出异常

语法: throw;

语义:重新抛出原有的异常对象。如果在throw后面有表达式,则抛出新的异常对象。

例子程序:

#include <iostream>
using namespace std;

void fun(int x){
 try{
  if(x == 1)
   throw 1;
  if(x == 2)
   throw 1.0;
  if(x == 3)
   throw ''1'';
 }catch(int){
  cout << "catch an int in fun()" << endl;
 }catch(double){
  cout << "catch an double in fun()" << endl;
 }
 cout << "testing exception in fun()..."<< endl;
}

void gun()
{
 try{
  //fun(1);
  //fun(2);
  //fun(3);
  fun(4);
 }catch(char){
  cout << "catch a char in gun()" << endl;
 }
 cout << "testing exception in gun()..."<< endl;
}

int main()
{
 gun();
}

4.扑获所有异常

catch(...){

}

下面的程序是不对的:

error C2311: ''int'' : is caught by ''...'' on line 7

#include <iostream>
using namespace std;

void fun()
{
 try{
 }catch(...){
  cout << "catch all exception ..." << endl;
 }catch(int){
  cout << "catch int exception ..." << endl;
 }
}

5.异常规范

指出函数可以抛出的所有异常类型名。

语法:值类型 函数名(形参表) throw(类型名表) 函数体

空异常规范表示不抛出异常;

例如:

warning C4297: ''function'' : function assumed not to throw an exception but does
        __declspec(nothrow) or throw() was specified on the function

#include <io

stream>
using namespace std;

void function(int x) throw()
{
 if(x == 1)
  throw 1;
}

无异常规范表示可抛出任何异常。

异常规范违例,在函数的声明中并没有声明抛出该类异常,但在程序中却抛出了该类的异常?例如:

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

void function(int x) throw (int)
{
 if(x == 1)
  throw 1.5;
}

注:在g++中并未警告。

对于函数指针,例如:

#include <iostream>
using namespace std;

void function(int x)throw(int)
{
        if(x == 1)
                throw 1;
}

int main()
{
        void (*fp)(int)throw(char);
        fp = function;
        fp(1);
}

同样的,在g++中没有警告,但在vc8中提出警告:

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

pan>

<补充>
异常规范违例,例子程序如下:

#include <iostream>
using namespace std;
class A
{
};

void function(int x)throw(int)
//void function(int x)throw(A*)
{
if(x == 1)
throw new A;
}

void test() throw (A* )
{
//void (*fp)(int)throw(A);
void (*fp)(int)throw(int);
fp = function;
try{
fp(1);
}catch(int)
{
cout << "test" << endl;
throw;
}
}

int main()
{
try{
test();
}catch(A*){
cout << "test in main" <<endl;
}
return 0;
}
这个代码在vc8g++环境中的运行结果不同?
 

<
补充
>
1.
异常处理仅仅通过类型而不是通过值来匹配的,否则又回到了传统的错误处理技术上去了,所以catch块的参数可以没有参数名称,只需要参数类型,除非要使用那个参数。

2.
虽然异常对象看上去像局部对象,但并非创建在函数栈上,而是创建在专用的异常栈上,因此它才可以跨接多个函数而传递到上层,否则在栈清空的过程中就会被销毁。

3.
函数原型中的异常说明要与实现中的异常说明一致,否则容易引起异常冲突。由于异常处理机制是在运行时有异常时才发挥作用的,因此如果函数的实现中抛出了没有在其异常说明列表中列出的异常,则编译器并不能检查出来。但是当运行时如果真的抛出了这样的异常,就会导致异常冲突。因为你没有提示函数的调用者:该函数会抛出一种没有被说明的即不期望的异常,于是异常处理机制就会检测到这个冲突并调用标准库函数unexcepted()unexcepted()的默认行为就是调用terminate()来结束程序。

实际工作中使用set_unexcepter()来预设一个回调函数。

4.
当异常抛出时局部对象如何释放?

Bjarne Stroustrup
引入了“resource acquistion is initialization”思想,异常处理机制保证:所有从trythrow语句之间构造起来的局部对象的析构函数将被自动调用,然后清退堆栈(就像函数正常退出一样)。如果一直上溯到main函数后还没有找到匹配的catch块,那么系统调用terminate()终止整个程序,这种情况下不能保证所有局部对象会被正确地销毁。

5.catch
块的参数应采用引用传递而不是值传递,不仅可以提高效率,还可以利用对象的多态性。另外,派生类的异常扑获要放到父类异常扑获的前面,否则,派生类的异常无法被扑获。catch(void *)要放到catch(...)前面。

6.
编写异常说明时,要确保派生类成员函数的异常说明和基类成员函数的异常说明一致,即派生类改写的虚函数的异常说明至少要和对应的基类虚函数的异常说明相同,甚至更加严格,更特殊。
 
 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 异常处理 入门 的相关文章

  • 为什么在连接两个字符串时 Python 比 C 更快?

    目前我想比较 Python 和 C 用来处理字符串的速度 我认为 C 应该比 Python 提供更好的性能 然而 我得到了完全相反的结果 这是 C 程序 include
  • 使用 C# 登录《我的世界》

    我正在尝试为自己和一些朋友创建一个简单的自定义 Minecraft 启动器 我不需要启动 Minecraft 的代码 只需要登录的实际代码行 例如 据我所知 您过去可以使用 string netResponse httpGET https
  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • 在c#中执行Redis控制台命令

    我需要从 Redis 控制台获取 客户端列表 输出以在我的 C 应用程序中使用 有没有办法使用 ConnectionMultiplexer 执行该命令 或者是否有内置方法可以查找该信息 CLIENT LIST是 服务器 命令 而不是 数据库
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • C# 数据表更新多行

    我如何使用数据表进行多次更新 我找到了这个更新 1 行 http support microsoft com kb 307587 my code public void ExportCSV string SQLSyntax string L
  • 使用 GCP 的数据存储区时如何区分代码是在模拟器中运行还是在 GKE 中运行

    按照中给出的说明进行操作后 我不确定是否遗漏了任何内容https cloud google com datastore docs tools datastore emulator https cloud google com datasto
  • 为什么将模块级代码放入函数中然后调用该函数在Python中速度更快?

    在亚历克斯 马尔泰利的回应中使 Python 脚本面向对象 https stackoverflow com questions 1813117 making a python script object oriented 他提到在 Pyth
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • IQueryable 单元或集成测试

    我有一个 Web api 并且公开了一个端点 如下所示 api 假期 name name 这是 Web api 的控制器 get 方法 public IQueryable
  • C++ int 前面加 0 会改变整个值

    我有一个非常奇怪的问题 如果我像这样声明一个 int int time 0110 然后将其显示到控制台返回的值为72 但是当我删除前面的 0 时int time 110 然后控制台显示110正如预期的那样 我想知道两件事 首先 为什么它在
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 检测到严重错误 c0000374 - C++ dll 将已分配内存的指针返回到 C#

    我有一个 c dll 它为我的主 c 应用程序提供一些功能 在这里 我尝试读取一个文件 将其加载到内存 然后返回一些信息 例如加载数据的指针和内存块的计数到 c Dll 成功将文件读取到内存 但在返回主应用程序时 程序由于堆损坏而崩溃 检测
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • 这个可变参数模板示例有什么问题?

    基类是 include
  • 如何减少具有多个单元的 PdfPTable 的内存消耗

    我正在使用 ITextSharp 创建一个 PDF 它由单个 PdfTable 组成 不幸的是 对于特定的数据集 由于创建了大量 PdfPCell 我遇到了内存不足异常 我已经分析了内存使用情况 我有近百万个单元格的 1 2 在这种情况下有
  • Objective-C / C 给出枚举默认值

    我在某处读到过关于给枚举默认值的内容 如下所示 typedef enum MarketNavigationTypeNone 0 MarketNavigationTypeHeirachy 1 MarketNavigationTypeMarke
  • 不区分大小写的字符串比较 C++ [重复]

    这个问题在这里已经有答案了 我知道有一些方法可以进行忽略大小写的比较 其中涉及遍历字符串或一个good one https stackoverflow com questions 11635 case insensitive string

随机推荐

  • Mysql中的连接方式

    1 内连接 内连接查询的是两张表的交集 也就是A表和B表都必须有数据才能查询出来 join和on是一起的 select from A join B on A id B id select from A inner join B on A i
  • springboot项目接口给null给前端返回空字符串。

    代码 Configuration public class JacksonConfig Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageCo
  • 使用docker搭建Grafana+influx 实时监控Jmeter压测平台

    准备工作 jmeter 压测工具 产生压测数据 IfluxDB 开源时序数据库 特别适合用于处理和分析资源监控数据 用于存储压测数据 Grafana 度量分析与可视化图标展示工具 可以支持不用种类的数据源 用于将存储于InfluxDB中的数
  • Qt实现图片的简单压缩

    在编程过程中 涉及到网络传输或资源加载时 过大的图片往往是编程人员的噩梦 加载时间过长 体验效果差 特别在即时通讯的发送图片时 大图往往半天加载不出来 于是 先对图片进行压缩 暂时显示模糊图片 然后下载大图最后更新下载的大图 这一过程成为解
  • 任务长期不释放和占用单节点持续的cpu,导致hivesever2本身内存泄漏造成

    任务长期不释放和占用单节点持续的cpu 导致hivesever2本身内存泄漏造成 产生的原因在于 查询过于复杂或者数据量过大 当有复杂的查询或处理大量数据的请求时 HiveServer2可能会出现高负载 这可能涉及大量的计算 IO操作或涉及
  • macm1环境下jdk版本切换

    macm1环境下jdk版本切换 本文目录 macm1环境下jdk版本切换 下载jdk 安装 动态切换jdk 终端生效 全局生效 参考 下载jdk oracle官方源下载地址 https www oracle com java technol
  • 一个新的微型JSON开源框架

    Snack3 一个新的微型JSON框架 一个作品 一般表达作者的一个想法 因为大家想法不同 所有作品会有区别 就做技术而言 因为有很多有区别的框架 所以大家可以选择的框架很丰富 snack3 基于jdk8 60kb 无其它依赖 非常小巧 强
  • OperationalError: (2005, "Unknown MySQL server host 'localhost' (11001)")

    在调试Django时突然报OperationalError 2005 Unknown MySQL server host localhost 11001 这个错误 根据提示信息判断是说mysql server 无法识别 localhost
  • $nextTick的作用和使用场景

    nextTick的作用和使用场景 vue中的nextTick主要用于处理数据动态变化后 DOM还未及时更新的问题 用nextTick就可以获取数据更新后最新DOM的变化 适用场景 第一种 有时需要根据数据动态的为页面某些dom元素添加事件
  • 解决延迟有 Wi-Fi 6 就够了!

    最近二狗子家里的路由器坏了 而家里的数据网络信号又非常差 失去了路由器基本上就等于和世界隔离 所以二狗子打算去附近商城随便买一个新的路由器 结果售货员张口就问 买 Wi Fi 6 的路由器吗 Wi Fi 6 这直接把二狗子问懵了 Wi Fi
  • Serverless Kubernetes 应用部署及扩缩容

    作者 邓青琳 轻零 阿里云技术专家 导读 本文分为三个部分 首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署 其次介绍 Serverless Kubernetes 的常用功能 最后对应用扩缩容的操作进行
  • 医学图像分割研究思路

    医学图像分割的主流方法之一是基于水平集 Level Set 的分割方法 目前针对主流的分割方法 我们主体研究思路如下图 在模型凸化以及形状先验两个方面 未开展相关工作 参考文献 部分演示代码 参数随图像需要调整 7 Xiaomeng Xin
  • 重新生成一堆rpm目录的repo库步骤

    createrepo c repo2module s stable modules yaml modifyrepo c mdtype modules modules yaml repodata
  • IntelliJ IDEA插件搜索下载缓慢

    我用的版本是2019 2 1 搜索插件特别慢 有时候加载不出来 看到别人说是用 Setting Appearance Behavior Syetem Setting Updates 将Use secure connection 的勾选去掉
  • java----面向对象和面向过程

    1 面向对象思想 面向对象四星思想就是把关注点放在一件事或一个活动中设计的人或事物上的思想 2 面向过程思想 面向过程思想就是把关注点放在一件事或一个活动中设计的人或事物所涉及的步骤上的思想 3 面向过程关键字 步骤 过程 4 面向对象关键
  • 一周 8k Star 的 Notion 开源替代品 AppFlowy 诞生

    近日 Notion 的开源替代品 AppFlowy 正式发布了 一经发布 在短短一周就获得了近 8k Star 这个成绩对于一个开源项目来说是非常不错的 那么为什么有了 Notion AppFlowy 团队却要从头开始开发一个类似的产品呢
  • 框架--SpringWeb

    文章目录 一 springweb 1 概述 2 springWeb层搭建 3 请求中的地址如何定义 4 如何接收请求中的数据 5 直接使用对象接收 6 post请求中文乱码处理 7 Ajax 返回 JSON 8 跨域问题 9 拦截器 10
  • string头文件常用方法(C++)

    string 定义字符串 如果未赋初值 则默认是 即空字符串 结尾也没有结束标志 0 include
  • 排序算法-希尔排序

    属性 1 希尔排序是对直接插入排序的优化 2 当gap gt 1时都是预排序 目的是让数组更接近于有序 当gap 1时 数组已经接近有序的了 这样就会很 快 这样整体而言 可以达到优化的效果 我们实现后可以进行性能测试的对比 3 希尔排序的
  • C++ 异常处理 入门

    C 异常处理 入门 异常 程序执行期间 可检测到的不正常情况 例如 0作除数 数组下标越界 打开不存在的文件 远程机器连接超时 malloc失败等等 程序的两种状态 正常状态和异常状态 发生不正常情况后 进入异常状态 从当前函数开始 按调用