看
为什么C++ exception handling需要unwind stack?
为什么throw会被抛弃?
throw() specification 可以让程序员在自己写的函数上标注该函数是否会抛出异常, 会抛出哪些类型的异常,但是throw有如下的问题:
1. C++基于throw的异常处理部分是一个“Shadow Type System”
为什么这么说呢?throw()语法有时被认为是函数签名的一部分,而有的时候却不允许,而这没有标准规定,比如下面的例子
1
2
3
4
5
6
7
8
// Example 2(a): You can’t write an ES
// in a typedef.
//
void f()throw(A,B);
typedef void (*PF)()throw(A,B);// syntax error
PF pf = f;// can’t get here
在typdef时不把throw作为函数类型的一部分,但看下面的例子:
1
2
3
4
5
6
// Example 2(b): But you can if you omit
// the typedef!
//
void f()throw(A,B);
void (*pf)()throw(A,B);// ok
pf = f;// ok
还有函数指针的例子:
1
2
3
4
5
6
// Example 2(c): Also kosher, low-carb,
// and fat-free.
//
void f()throw(A,B);
void (*pf)()throw(A,B,C);// ok
pf = f;// ok, less restrictive
还有继承的virtual 函数的例子:
1
2
3
4
5
6
7
8
9
10
11
12
// Example 2(d): And the ES in the signature
// does matter if it’s a virtual function.
//
class C
{
virtual void f()throw(A,B);// same ES
};
class D : C
{
void f();// error, now the ES matters
};
2. 对throw语法的(错误)理解
很多人认为throw表示下面的意思:
1. Guarantee that functions will only throw listed exceptions (possibly none).
2. Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown.
对第一条,看下面的代码:
1
2
3
4
5
6
// Example 1(b) reprise, and two
// potential white lies:
//
int Gunc()throw();// will throw nothing (?)
int Hunc()throw(A,B);// can only throw A or B (?)
Gunc()真的不会throw任何异常吗?Hunc()真的只会抛出类型A和B的异常吗?不是的,代码复杂、调用嵌套多次后,很多时候程序员是无法准确标注这个函数会throw什么样的exception。而一旦未被标注的异常发生后,编译器也只是默默地做点事情,而这对我们的程序没有什么帮助。如果一个未被标准的异常发生后,编译器就调用std::unexpected()函数。unexpected()函数是全局的,很难对特定的exception提供很有帮助的处理,大部分情况就直接terminate,而且unexpected()函数是不会返回的,所以,这样的异常一旦发生,就等于退出程序。
对throw的理解应该换成下面的两句:
Guarantee Enforce at runtime that functions will only throw listed exceptions (possibly none).
Enable or prevent compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown having to check whether listed exceptions are indeed being thrown.
下面看看编译器干了什么,对下面的代码:
1
2
3
4
5
6
// Example 3(a)
//
int Hunc()throw(A,B)
{
return Junc();
}
编译器生成如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Example 3(b): A compiler’s massaged
// version of Example 3(a)
//
int Hunc()
try
{
return Junc();
}
catch( A )
{
throw;
}
catch( B )
{
throw;
}
catch( ... )
{
std::unexpected();// will not return! but
}// might throw an A or a B if you’re lucky
可见,编译器并不是根据listed exception做优化,编译器需要生成更多的代码来保证在运行时只有listed exception被throw出来,而没有list就调用unexpected函数了。
在回头看对throw的正确的理解:
1. 保证运行时,只会throw listed exception,而如果发生不listed 的exception,那就调用unexpected;
2. 允许或者禁止编译器不得不进行是否listed exception发生的检查。
在上面说明了使用throw时,编译器需要生成try-catch代码, 其实throw还有其他问题:1. 有些编译器会自动拒绝为使用throw的function做inline优化;2. 有些编译器不回去对与exception有关的知识进行优化,即使有些代码绝不会throw exception,但编译器还是会生成try-catch代码。3. throw在virtual函数中时signature的一部分,所以,如果你把base class 的virtual方法中throw的类型之一或者若干个去掉了,那就也需要更新子类的代码,这样实际上增加了coupling,是很不好的设计。
所以关于throw,建议是
Moral #1: Never write an exception specification.
Moral #2: Except possibly an empty one, but if I were you I’d avoid even that.
现在大家都做cross-platform的开发,多一事不如少一事,throw不会带来什么好处,所以,就完全不要用了。
既然throw有如此多的问题,那C++11带来了什么呢?
Reference:
原文转自:http://www.cnblogs.com/whyandinside/p/3677589.html
原作者为:做个不善的人. 请尊重原作者版权
C++异常处理assert,throw,exit用法
常见的几个小细节问题. assert应用: 在现实世界中,我们脑袋时刻都在判断对与错,对的事情我们会继续深入下去,而错的事情我们会马上停止,那么在编程开发中我们如何赋予程序这种判断事物对错的能力呢?其 ...
java异常处理之throw, throws,try和catch
转自 http://blog.csdn.net/zhouyong80/article/details/1907799 程序运行过程中可能会出现异常情况,比如被0除.对负数计算平方根等,还有可能会出现 ...
异常处理(throw,throws,try,catch,finally)
一.异常 1.定义:程序在运行时出现的不正确的情况. 2.由来:问题也是生活中的事物,也可以被Java描述,并被封装成对象. 其实就是Java对不正常情况进行描述后的对象体现. 3.划分:Java对于 ...
java异常处理的throw和throws的区别
1. 区别 throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是指抛出的一个具体的异常类型. 2.分别介绍 ...
六. 异常处理7.throw:异常的抛出
到目前为止,你只是获取了被Java运行时系统抛出的异常.然而,程序可以用throw语句抛出明确的异常.Throw语句的通常形式如下: throw ThrowableInstance;这里,Thr ...
Swift异常处理:throw和rethrow
Swift异常处理体现了函数式语言的特性.因此我们能够传一个会抛出异常的函数闭包(高阶函数)作为參数传到还有一个函数中(父函数),父函数能够在子函数抛出异常时直接向上抛出异常,这时用rethrowke ...
java中异常处理机制 throw抛出自定义业务逻辑异常 throws继续抛出 catch捕获后会自动继续抛向调用方法
package com.swift; public class Exception_TestC { public static void main(String[] args) { /* * 第5题: ...
C++11异常处理 noexcept
1.简介 在C语言中,如果程序的运行出现异常.错误,我们想提供方案处理这些异常时,我们面临许多问题,如: (1)C语言没有提供统一(标准)的方式来处理错误: (2)无法保证错误会被正确的处理: (3) ...
随机推荐
Unity 利用NGUI做屏幕分辨率适配+学习UIDraggablePanel的使用
原地址:http://blog.sina.com.cn/s/blog_697b1b8c0101g2r4.html 大家使用unity,一定有看中其跨平台的强大功能,因此也难免会遇到不同屏幕分辨率适配的 ...
多线程编程之二 ---MFC中的多线程开发
下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...
深入研究Java类载入机制
深入研究Java类载入机制 类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...
linux通用邻居基础架构
1.为每一个协议提供一个缓存来存放L3到L2的转换结果. 2.提供在缓存中添加.删除.改变和查找一个特定映射项的函数.查找函数必须要快,因为它会影响整个系统的性能. 3.为每一个协议缓存的数据项提供一 ...
ZenCoding 个人理解和总结
我的理解:ZenCoding是一个html简写的语法,可以最快速的生成html. 不少IDE应该都支持,我用的intellij idea是支持的. ZenCoding表示和CSS/JS有相通之处,比如 ...
如何从0开发一个Atom组件
最近用Atom写博客比较多,然后发现一个很严重的问题..没有一个我想要的上传图片的方式,比如某乎上边就可以直接copy/paste文件,然后进行上传.然而在Atom上没有找到类似的插件,最接近的一个, ...
Dll的编写 在unity中加载
1. 在VS中新建Dll项目 2.在头文件中对函数进行声明 extern "C" int _declspec(dllexport) testunity(); 3.在源文件中写函数体 ...
loadrunner 脚本开发-基本知识
脚本开发-基本知识 1)编码工具设置 自动补全输入Tools->General Options->Environment->Auto complete word 显示功能语法Tool ...
[No0000100]正则表达式匹配解析过程分析(正则表达式匹配原理)&regexbuddy使用&正则优化
常见正则表达式引擎引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎有:DFA,NFA两种引擎. 引擎 区别点 DFA Deterministic finite autom ...