C++异常

16 篇文章 0 订阅

C语言异常处理

C语言中最常用的处理简单错误的方式就是通过 assert , 错误码 以及 perror等库函数来进行错误的获取和处理. 但是这存在一些缺陷, 比如说 assert 直接终止程序太粗暴, 错误码在返回值为整型家族的函数中会难以判断.
setjmp.h
在C语言的函数库中存在 setjmp 和 longjmp 的组合, 来实现简单的异常捕获和处理. 这在较大型的C语言项目中可能会用到.

#include <stdio.h>    
#include <setjmp.h>    
    
jmp_buf jb; // 定义状态    
    
double divison(double a, double b) {                                                                            
  if (b == 0) {    
    longjmp(jb, -1); // 类似于 throw    
  } else {    
    return (double)a / (double)b;    
  }    
}    
void printError(int e_id) {    
  if (e_id == -1) {    
    printf("除数为 0 ...\n");    
  } else {    
    printf("未知错误...\n");    
  }    
}    
int main() {    
  int e = setjmp(jb); // 设置异常状态, 初始为 0    
  if (e == 0) {    // 类似于 try
    printf("%f\n", divison(4, 0));// 异常回到setjmp, 修改e    
  } else {    // 类似于 catch
    printError(e);    
  }    
  return 0;    
}    

C++异常处理

异常可以认为是处理错误的一种方式, 当一个函数发现自己无法处理该错误时就可以选择抛出异常(throw), 让某个函数直接或间接的捕获(try)并处理(catch)这个异常.
异常的抛出, 捕获和处理:
异常可以抛出任意类型的对象, 在处理异常时根据抛出对象的类型进行匹配处理.

#include <iostream>    
using namespace std;    
double division(const double a, const double b) {    
  if (b == 0) {    
    throw "divisor is zero...";    
  } else {    
    return (double)a / (double)b;    
  }    
}    
void Fun() {    
  double a  = 0, b = 0;    
  cout << "请输入 2 个数:" ;    
  cin >> a >> b;    
  cout << "相除结果为 " << division(a, b) << endl;    
}    
void Exception() {    
  try {    
    Fun();    
  } catch (const char* errmsg) {    
    cout << __LINE__ << ":" << errmsg << endl;    
  } catch (...) { // 不知道是什么异常, 即处理任何异常   
    cout << "unknown exception" << endl;    
  }    
}    
int main() {    
  Exception();    
  return 0;    
}                               

在这里插入图片描述
在函数调用链中, 抛出对象最先被里自己最近的异常函数捕获:

void Fun() {    
  double a  = 0, b = 0;    
  cout << "请输入 2 个数:" ;    
  cin >> a >> b;    
  try {    
    cout << "相除结果为 " << division(a, b) << endl;    
  } catch (const char* errmsg) {    
    cout << __LINE__ << ":" << errmsg << endl;    
  }    
}    
// 在 Exception 函数中调用了 Fun, 并且两个函数都进行了异常的捕获, 但是Fun离在调用链中离抛出对象更近, 最先被调用处理, 后面则不再被处理

在这里插入图片描述异常的重新抛出:
一般在两个常见的场景下会使用异常的重新抛出, 分别是释放对内存和请求重试

void Fun() {    
  int* num = new int(1);    
  double a  = 0, b = 0;    
  cout << "请输入 2 个数:" ;    
  cin >> a >> b;    
  try {    
    cout << "相除结果为 " << division(a, b) << endl;    
  } catch (...){    
    cout << "delete num" << endl;    
    delete num;                                                                                                 
    throw; //再次抛出, 让 divisor 为 0 的异常继续抛出    
  }    
  cout << "deleted" << endl;    
  delete num;    
}    

在这里插入图片描述

#include <iostream>    
using namespace std;    
int num = 0;    
int getNum() {    
  if (num != 0) {    
    --num;                                                                                                      
    throw "num is not zero";    
  } else {    
    return num;    
  }    
}    
void Catch() {    
  int choice = 5;    
  while (choice--) { //重试 5 次    
    try {    
      cout << getNum() << endl;    
      break;    
    } catch(const char* errmsg) {    
      cout << errmsg << endl;    
    } catch(...) {    
      cout << "Unknown error" << endl;    
    }    
  }    
  if (choice <= 0) {
    cout << "failed..." << endl;
  } else {
    cout << "successed..." << endl;
  }
}
int main() {
  cout << "please input a num:" << endl;
  cin >> num;
  Catch();
  return 0;
}                            

在这里插入图片描述
异常安全:
1.构造函数完成对象的构造和初始化,最好不要在构造函数中抛出异常,否则可能导致对象不完整或没有 完全初始化
2.析构函数主要完成资源的清理,最好不要在析构函数内抛出异常,否则可能导致资源泄漏(内存泄漏、句 柄未关闭等)
3.C++中异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄漏,在lock和 unlock之间抛出了异常导致死锁,C++经常使用RAII来解决以上问题
异常规范:
1.异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。 可以在函数的后面接 throw(类型),列出这个函数可能抛掷的所有异常类型。
2.函数的后面接throw(),表示函数不抛异常。
3.若无异常接口声明,则此函数可以抛掷任何类型的异常

// 这里表示这个函数会抛出A/B/C/D中的某种类型的异常 
void fun() throw(A,B,C,D); 
// 这里表示这个函数只会抛出bad_alloc的异常
void* operator new (std::size_t size) throw (std::bad_alloc); 
// 这里表示这个函数不会抛出异常 
void* operator new (std::size_t size, void* ptr) throw();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值