0
点赞
收藏
分享

微信扫一扫

C++ 异常处理机制

梅梅的时光 2022-03-31 阅读 63
c++c#

异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。典型的异常包括失去数据库连接以及遇到意外输入等。目前觉得相对适用的就是what、when、why和how,下面是在笔记中记录的一段话,,它从语言设计的层面考虑了 C++中为什么添加异常,觉得很棒,分享给大家:

接下来,来了解 C++的异常处理机制。

C++异常处理机制通过异常检测和异常处理两部分进行支持,包括:

  • throw表达式,异常检测部分使用throw表达式抛出异常。

  • try语句块,异常处理部分采用try语句块进行异常处理,try语句块以关键字try开始,并以一个或多个catch子句结束。try语句块中代码抛出的异常通常会被某个catch子句处理。因为catch子句“处理”异常,所以它们也被称作异常处理代码(exception handler)。

  • 一套异常类,用于在throw表达式和相关的catch子句之间传递异常的具体信息,C++中提供了标准exception

简单的异常处理

在 C++标准库定义了一组类,用于报告标准库函数遇到的问题。这些异常类也可以在用户编写的程序中使用,它们分别定义在 4 个头文件中:

  • exception 头文件定义了最通用的异常类 exception。它只报告异常的发生,不提供任何额外信息。

  • stdexcept头文件定义了几种常用的异常类

  • new头文件定义了bad_alloc异常类型,默认,如果new不能分配所要求的内存空间,它会抛出一个类型为bad_alloc的异常。我们可以改变使用 new 的方式来阻止它抛出异常:

// 如果分配失败,new抛出std::bad_alloc
int *p1 = new int;

// 如果分配失败,new返回一个空指针
int *p2 = new (nothrow) int;

type_info 头文件定义了 bad_cast 异常类型,dynamic_cast<type&>(e)如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个bad_cast异常。

#include <iostream>
#include <exception>

void tryException() {
  	// 此处是模拟处理出现问题,抛出异常
    throw std::runtime_error("This's just exception test!");
}

int main(int argc, char* argv[]) {
    try {
        tryException();
    } catch(const std::runtime_error& e) {
        std::cout << "catch runtime_error for " << e.what() << std::endl;
    }
}

函数在寻找处理代码的过程中退出

LinuxC++服务器开发视频c/c++ linux服务器开发/后台架构师-点击观看

需要C/C++ Linux服务器架构师学习资料加994289133获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享。

异常规格

异常规格对函数定义进行限定,指出其可能引发那些类型的异常,同时提醒程序员此处可能抛出异常应该使用try-catch和处理程序,其由 throw 关键字和异常类型列表组成,异常类型括在括号中,用逗号分割。函数的异常规格不仅要包含自身触发的异常类型,还要调用其他函数可能触发的异常类型。异常规则在 C++11 中被舍弃,在 C++17 中被彻底移除,改用noexcept(true)noexcept(false),前者表示该实现无异常抛出,后者表示所有的异常。

// 可能抛出任何异常
void func();

// 只能抛出char*和int类型的异常
void func() throw(const char*, int); 

// 不抛出任何异常
void func() throw();

意外异常

如果带异常规格的函数抛出了和规格列表中不匹配的异常,称之为意外异常,会调std::unexpected,该函数默认会调用std::terminate,用户也可以通过std::set_unexpected设定用户自己设定的行为

typedef void (*unexpected_handler)();
unexpected_handler set_unexpected(unexpected_handler f) throw();
void unexpected();

unexpected_handler函数行为遵守严格的限制:

  • 通过调用terminate(默认)、abort()exit()来终止程序。

  • 引发异常,结果取决于unexpected_handler函数所引发的异常以及引发意外异常的函数异常规范:

  • 新引发的异常和原异常规范匹配,则程序寻找与新引发异常匹配的catch块,该行为相当于用预期异常取代意外异常。

  • 新引发的异常和原异常规范不匹配且异常规范没有std::bad_exception类型,则程序将调用terminate()

  • 新引发的异常和原异常规范不匹配且异常规范包含std::bad_exception类型,则不匹配的异常将被std::bad_exception异常所取代

#include <iostream>
#include <exception>

void myUnexpected() {
    std::cout << "catch unexpected exception!" << std::endl;
  	// 1. 将意外异常统一转化为bad_exception,或者其他的异常
  	// throw std::bad_exception();
  	
  	// 2. 抛出和异常规格匹配的异常,程序寻找匹配的catch处理块
    throw "----------- satify exception specification --------";
}

// 异常规格,该接口支持抛出const char*的异常
// void handleMessage() throw(const char*, std::bad_exception){ // for understanding
void handleMessage() throw(const char*)  {
    std::cout << __func__ << std::endl;
    throw std::underflow_error("error::underflow");
} 

int main(int argc, char* argv[]) {   
    try {
        std::set_unexpected(myUnexpected);
        handleMessage();
    } catch (const char* e) {
        std::cout << e << std::endl;
    } catch (std::bad_exception& e) {
        std::cout << "catch bad_exception: " << e.what() << std::endl;
    }
    return 0;
}

 

未捕获异常

没有try块或者catch块时,异常未捕获,称之为未捕获异常。默认,将会导致程序异常终止。也可以修改程序对意外异常和未捕获异常的反应。未捕获的异常,通常不会立刻导致程序终止,程序首先会调用terminate()此时会调用std::abort()函数,我们可以修改terminate()的实现来实现行为定制。相关接口定义:

typedef void (*terminate_handler)();
terminate_handler set_terminate(terminate_handler f) throw();
void terminate();

假设程序抛出了一个未捕获的运行时异常,并自定义终止terminate_handler

#include <iostream>
#include <exception>

void myTerminateHandler() {
    std::cout << "Error catch uncatched exception!" << std::endl;
    exit(-1);
}

int main(int argc, char* argv[]) {
    // 自定义terminate_handler行为
    std::set_terminate(myTerminateHandler);
    // 抛出一个未捕获的异常,将会触发terminate_handler
    throw std::runtime_error("This's just a test");
    return 0;
}

 

举报

相关推荐

0 条评论