堆栈辗转开解(stack-unwinding):如果一个函数中出现异常,在当前函数内即通过 try..catch 捕捉(且捕捉到)的话,可以继续往下执行;如果不捕捉(或未捕捉到)就会抛出(与通过 throw 显式抛出效果相同)到外层函数,则当前函数会终止运行,释放当前函数内的局部对象(局部对象的析构函数就自然被调用了),外层函数如果也没有捕捉到的话,会再次抛出到更外层的函数,该外层函数也会退出,释放其局部对象……如此一直循环下去,直到找到匹配的 catch 子句,如果找到 main 函数中仍找不到,则调用名为 terminate 的标准库函数,该函数在 exception 头文件中定义,导致程序非正常退出。可以通过 std::set_terminate(fun) 来指定 terminate 调用的函数来输出一些信息。

异常是通过抛出对象而引发的,抛出的对象类型决定应该激活哪个处理代码,被选中的处理代码是距离抛出异常最近的匹配的 catch 子句。

#include <iostream>
#include <string> void fun1() { throw "this is char* exception"; } void fun2() { throw std::string("this is string exception"); } int main()
{
try
{
fun1();
}
catch(const char* e)
{
std::cout<<e<<std::endl;
}
try
{
fun2();
}
catch(std::string& e)
{
std::cout<<e<<std::endl;
}
}

标准库异常类:

1、#include <exception>

定义了最常见的异常类,类名是 exception ,这个类只通知异常的产生,不提供更多信息。被 <stdexcept> 头文件包含

2、#include <stdexcept>

定义了几种常见的异常类,如: exception,runtime_error,range_error,out_of_range 等,都是 exception 的子孙类。

3、#include <new>

定义了 bad_alloc 异常类

4、#include <type_info>

定义了 bad_cast 异常类

标准异常类型只定义了 what() 函数,返回 const char* 字符串,用来提供详细的异常描述信息。what() 返回什么,是由标准异常类的构造函数决定的,像 exception, bad_alloc, bad_cast 类型只有默认构造函数,所以错误信息是不可定制的,而其它标准异常类如 runtime_error 只定义了一个带 string 参数的构造函数,这种异常类型的 what() 就可以在构造函数时定制了。

#include <iostream>#include <stdexcept>

void fun() { throw std::runtime_error("this is my runtime_error"); }

void fun2() { throw std::exception(); }

int main()
{
try
{
fun();
fun2();
}catch(std::runtime_error& e)
{
std::cout<<e.what()<<std::endl;
}
catch(std::exception& e)
{
std::cout<<e.what()<<std::endl;
}
}

可以自定义异常类,继承 exception ,实现 what() 函数:

#include <iostream>
#include <string>
#include <exception> class MyException : public std::exception
{
std::string error_msg; public:
explicit MyException(const std::string& _error_msg):error_msg(_error_msg) { }
const char* what()
{
return error_msg.c_str();
}
~MyException() noexcept{}
//旧式写法: ~MyException() throw(){}
//throw(int) 只能抛出 int 型异常;throw() 不抛出任何异常
//throw() 已经被 c++11 标记为过时,被 noexcept 取代
}; void fun() { throw MyException("this is myexception"); } int main()
{
try
{
fun();
}
catch(MyException& e)
{
std::cout<<e.what()<<std::endl;
}
}

不继承 exception 类,也可以使用,那继承它有什么好处呢?

1、统一的规范的接口,what() 函数。
2、可以在捕捉语句中使用 catch(std::exception& e) 来捕捉。

如果被抛出的异常对象是派生类类型的,但由基类类型的 catch 处理,那么,catch 不能使用派生类的特有的任何成员,也不会有多态行为产生。

另外,通过 catch(...) 可以捕捉所有的异常,包括自定义的异常(也包括不从 exception 继承的异常)。如果这样来看,其实不从 exception 继承也没什么,最后使用 catch(...) 把关。

析构函数应该禁止抛出异常,因为当抛出异常时,局部对象析构,而如果此时该局部对象析构函数里也抛出异常的话,则 C++ 无法同时处理两个异常,就会调用 terminate 函数终止程序。如果析构函数里存在异常,应该在析构函数内部处理,而不应当抛出。

构造函数中可以抛出异常,但发生异常时,该对象可能只是部分被构造,由于对象没有构造完成,不会执行析构函数,所以要自己保证能适当的撤销已构造的成员。C++拒绝为没有完成构造函数的对象调用析构函数,原因是避免开销,因为只有在每个对象里加一些字节来记录构造函数执行了多少步,它会使对象变大,且减慢析构函数的运行速度。所以只能自己手动进行资源释放,比较麻烦。一般建议不要在构造函数里做过多的资源分配,而应该把这些操作放在一个类似于 init 的成员函数中去完成。这样当 init 成员函数抛出异常时,如果对象是在栈上,析构函数仍会被调用(异常会自动销毁局部对象,调用局部对象的析构函数),如果是在堆上,需要在捕获异常之后 delete 对象来调用析构函数。

在 catch 子句中,可以通过 throw; 重新抛出异常。

c++异常总结的更多相关文章

  1. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  2. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  3. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  4. 使用JSONObject.fromObject的时候出现“There is a cycle in the hierarchy”异常 的解决办法

    在使用JSONObject.fromObject的时候,出现“There is a cycle in the hierarchy”异常.   意思是出现了死循环,也就是Model之间有循环包含关系: ...

  5. SignalR代理对象异常:Uncaught TypeError: Cannot read property 'client' of undefined 推出的结论

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#signalR 后台创建了一个DntHub的集线器 前台在调用的时候出现了问题(经检查是代理对象 ...

  6. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  7. [C#] C# 知识回顾 - 学会处理异常

    学会处理异常 你可以使用 try 块来对你觉得可能会出现异常的代码进行分区. 其中,与之关联的 catch 块可用于处理任何异常情况. 一个包含代码的 finally 块,无论 try 块中是否在运行 ...

  8. [C#] C# 知识回顾 - 学会使用异常

    学会使用异常 在 C# 中,程序中在运行时出现的错误,会不断在程序中进行传播,这种机制称为“异常”. 异常通常由错误的代码引发,并由能够更正错误的代码进行 catch. 异常可由 .NET 的 CLR ...

  9. [C#] C# 知识回顾 - 异常介绍

    异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...

  10. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

随机推荐

  1. Jenkins用HTTP Request Plugin插件进行网站的监控(运维监控)

    使用的插件: [HTTP Request Plugin] 思路: 说明:只能是网站是否正常打开,而不能是这个网站业务是否正常,如果是后者,则需要写特定的接口进行请求处理. 1.通过插件,发送GET请求 ...

  2. hdu3932 模拟退火

    模拟退火绝对是从OI--ACM以来接触过的所有算法里面最黑科技的orz 题意:地上有一堆hole,要找一个点,使得(距离该点最远的hole的距离)最小. sol:本来想套昨天的模拟退火模板,初值(0, ...

  3. 页面记载给绑定query的grid加filter

    功能名称:listDataAction 切入类型:before 事件名称:com.kingdee.bos.webframework.dynamic.event.view.WebListDataEven ...

  4. CF570D:Tree Requests

    传送门 DFS重标号+二分 打比赛的时候想了很多方法..DFS序,BFS序,倍增什么的都考虑了一遍,但是几乎要么是可以维护两个区间但是代码复杂度爆炸,要么就是只能维护单一维度的信息. 这道题的具体做法 ...

  5. 快捷键&小技巧&备忘录

    shift+鼠标滚轮:实现左右移动 alt+鼠标左键双击:打开属性 chrome中在F12下的Element中,可以先选中某一项,可以直接按住F2进行编辑 chrome中element的右下方我们可以 ...

  6. 日志模块logging使用心得

    在应用程序使用中,日志输出对应用维护人员.开发人员判断程序的问题起重要作用. 那么在python中如何定义程序的日志输出? 推荐使用日志模块logging 需求:实现日志内容输出在文件中和控制器中 i ...

  7. 线性回归和批量梯度下降法python

    通过学习斯坦福公开课的线性规划和梯度下降,参考他人代码自己做了测试,写了个类以后有时间再去扩展,代码注释以后再加,作业好多: import numpy as np import matplotlib. ...

  8. winform的tab跳到下一个

    先设置TabStop=true,再设置TabIndex的顺序

  9. JavaWeb学习笔记——开发动态WEB资源(四)打印当前使用的是get方法

    该工程的名称是testhttp,功能是在页面中表格打印浏览过程中的相关头信息. 新建一个工程,然后在这个工程里面新建一个servlet,这样便可以省去编写web.xml的过程 以下是TestHttpS ...

  10. Windows Platform Predefined Macros

    https://msdn.microsoft.com/en-us/library/b0084kay.aspx