c++学习笔记之异常

简介: 1、异常详细见《c++异常分类》基类exception有一个virtual函数what,返回错误信息(构造函数设定的)。基类exception的派生类有runtime_error(运行时错误,运行后检测)、logic_error(逻辑错误,运行前检测)和运算符抛出的异常。运算符抛出的异常包括:bad_alloc(new抛出),bad_cast(dynamic_cast抛出),bad_typeid(typeid抛出),bad_exception

1、异常


详细见《c++异常分类》

基类exception有一个virtual函数what,返回错误信息(构造函数设定的)。

基类exception的派生类有runtime_error(运行时错误,运行后检测)、logic_error(逻辑错误,运行前检测)和运算符抛出的异常。

运算符抛出的异常包括:bad_alloc(new抛出),bad_cast(dynamic_cast抛出),bad_typeid(typeid抛出),bad_exception


注意:

(1)如果一个函数抛出列表中包含bad_exception,那么如果一个意料之外的异常发生时,函数unexcpected将抛出bad_exception而不是结束程序,或调用set_unexpected指出的函数。


(2)自定义异常可以不继承exception,所以catch(exception)不能保证捕获所有异常


(3)catch(...)可以捕获所有异常,但是由于没有参数所以没法查找该异常。


2、throw


除了抛出异常,也可以抛出表达式值或int值,如throw x > 5 或 throw 5

重新抛出异常如下:

catch(xxxx){

    throw;

}

注意:在catch语句外有throw;语句会调用terminate函数,会导致程序结束。

注意:带有常见错误的函数应返回0或者NULL,而不是抛出异常。通过检查返回值确定调用是否成功。


3、异常说明


列举一系列函数可以抛出的异常,如:

void do(..) throw (ExceptionA, ExceptionB, ...){...}

注意:

(1)抛出一个异常说明不允许的异常,会调用unexpected函数。

       

(2)没有提供异常说明的函数可以抛出任何异常。在函数设置一个空异常说明throw()

表示该函数没有抛出任何异常,如果试图抛出异常,调用unexpected函数。


4、处理意料之外异常


unexpected函数会调用函数set_unexpected注册的函数,如果没有注册会默认调用terminate函数;

terminate函数会调用set_terminate注册的函数,如果没有默认调用abort函数。

调用terminate函数的四种情况:


(1)对抛出的异常,异常机制找不到匹配的catch块


(2)析构函数试图在堆栈展开时抛出一个异常


(3)在没有异常要处理是试图重新抛出异常(即第二条中的注意事项)


(4)调用函数unexpected将默认调用函数terminate


注意:set_unexpected和set_terminate会分别返回一个指向函数unexpected和terminate最后一次调用的函数的指针,如果第一次调用则返回0


注意:set_unexpected和set_terminate接收void返回值且没有参数的函数指针作为参数。

注意:如果自定的终止函数的最后行为并不是退出程序,那么这个函数执行完后会调abort终止程序。


5、堆栈展开


当一个异常被抛出但没有在一个特定的域内被捕获时,该函数调用堆栈就会展开,并试图在下一个外部try..catch内捕获。

展开 函数调用的堆栈,此函数中所有局部变量被销毁。


6、构造、析构函数和异常


构造函数可以抛出异常,异常抛出前会调用析构函数。

如果由于堆栈展开而调用析构函数抛出了一个异常,terminate函数被调用(terminate函数调用四个情况之一)。


7、处理new失败


编译器不同,处理方式不同,有三种:默认返回0;抛出异常(已包含头文件);默认抛出bad_alloc

set_new_handler可以注册一个new失败后的异常处理器。参数是一个没有参数且返回值为空的函数的指针。


注意:一旦注册在set_new_handler注册了,那么new失败时不会抛出bad_alloc,将错误堆栈推给new处理器来处理。

c++标准明确指出new处理器要完成以下任务的一个:


(1)释放其他动态分配内存,并返回运算符new来尝试再次分配内存


(2)抛出bad_alloc型异常


(3)调用函数abort或exit来结束程序


8、auto_ptr和动态分配内存


如果一个异常发生在成功分配内存后,delete语句前,那么发生内存泄漏。auto_ptr可以处理这种情况。

一个auto_ptr对象维护了指向动态分配内存的指针,当一个auto_ptr对象析构函数被调用,它将对其指针的数据成员执行delete。

由于auto_ptr类模板提供了重载运算符"*"和"->",auto_ptr对象可以作为一般指针变量使用。如:


auto_ptr<A> ptr(new A(...));
ptr->do(...)     //do函数是A类的成员函数
复制代码


注意:


(1)auto_ptr不能指向数组和标准容器类。


(2)auto_ptr能通过它的重载赋值运算符和拷贝构造函数来传递动态内存所有权


9、setjump和longjump


能够指定从一个深度嵌套调用中立即跳转到一个错误处理器(不必层层抛出)。但很危险,因为没有调用为自动对象建立的析构函数。

请注明出处。

目录
相关文章
|
25天前
|
安全 程序员 编译器
【C++】异常
C++异常处理机制允许在程序运行时出现错误时,通过`try`、`catch`和`throw`关键字将错误信息传递回调用栈,进行异常处理。它支持异常的重新抛出、自定义异常体系以及标准库提供的异常类层次结构,如`std::exception`及其派生类。异常处理提高了代码的健壮性和可维护性,但也带来了性能开销和代码复杂性等问题。合理使用异常机制,可以有效提升程序的稳定性和安全性。
43 3
|
4月前
|
C++
c++学习笔记07 结构体
C++结构体的详细学习笔记07,涵盖了结构体的定义、使用、数组、指针、嵌套、与函数的交互以及在结构体中使用const的示例和解释。
40 0
|
3月前
|
安全 C语言 C++
C++学习笔记
C++学习笔记
|
4月前
|
C++
c++学习笔记02 运算符
C++学习笔记,介绍了C++中的运算符,包括基本的加减乘除、求模、前后置递增递减、赋值运算符、比较运算符和逻辑运算符的使用及其注意事项。
42 6
|
4月前
|
C++
c++学习笔记01 基本知识与数据类型
C++学习笔记,涵盖了C++中的常量定义、数据类型、变量内存大小计算、基本数据类型(整型、实型、字符型、字符串型、布尔型)以及转义字符的使用。
48 4
|
4月前
|
算法 C++
c++学习笔记04 数组
这篇文章是C++学习笔记4,主题是数组。
47 4
|
4月前
|
C++
【学习笔记】【C/C++】 c++字面值常量
【学习笔记】【C/C++】 c++字面值常量
46 1
|
4月前
|
存储 C++
c++学习笔记05 函数
C++函数使用的详细学习笔记05,包括函数的基本格式、值传递、函数声明、以及如何在不同文件中组织函数代码的示例和技巧。
37 0
c++学习笔记05 函数
|
5月前
|
C++
C++ 异常机制问题之捕获异常的问题如何解决
C++ 异常机制问题之捕获异常的问题如何解决
|
4月前
|
编译器 C++
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
57 0