这篇文章学习C++异常处理的基础知识。看完后,还不过瘾,为什么大家在C++代码中都不用Exception?为什么C++11会引入一些变化?

为什么C++ exception handling需要unwind stack?

为什么throw会被抛弃?

接着看http://www.gotw.ca/publications/mill22.htm, 总结如下:

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:

1. http://www.learncpp.com/cpp-tutorial/153-exceptions-functions-and-stack-unwinding/

2. http://www.gotw.ca/publications/mill22.htm

3. http://stackoverflow.com/questions/88573/should-i-use-an-exception-specifier-in-c/88905#88905

4. http://stackoverflow.com/questions/10787766/when-should-i-really-use-noexcept

原文转自:http://www.cnblogs.com/whyandinside/p/3677589.html

原作者为:做个不善的人.  请尊重原作者版权

C++的异常处理之一:throw是个一无是处的东西的更多相关文章

  1. C++异常处理assert,throw,exit用法

    常见的几个小细节问题. assert应用: 在现实世界中,我们脑袋时刻都在判断对与错,对的事情我们会继续深入下去,而错的事情我们会马上停止,那么在编程开发中我们如何赋予程序这种判断事物对错的能力呢?其 ...

  2. java异常处理之throw, throws,try和catch

    转自 http://blog.csdn.net/zhouyong80/article/details/1907799  程序运行过程中可能会出现异常情况,比如被0除.对负数计算平方根等,还有可能会出现 ...

  3. 异常处理(throw,throws,try,catch,finally)

    一.异常 1.定义:程序在运行时出现的不正确的情况. 2.由来:问题也是生活中的事物,也可以被Java描述,并被封装成对象. 其实就是Java对不正常情况进行描述后的对象体现. 3.划分:Java对于 ...

  4. java异常处理的throw和throws的区别

    1. 区别 throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是指抛出的一个具体的异常类型. 2.分别介绍 ...

  5. 六. 异常处理7.throw:异常的抛出

    到目前为止,你只是获取了被Java运行时系统抛出的异常.然而,程序可以用throw语句抛出明确的异常.Throw语句的通常形式如下:    throw ThrowableInstance;这里,Thr ...

  6. Swift异常处理:throw和rethrow

    Swift异常处理体现了函数式语言的特性.因此我们能够传一个会抛出异常的函数闭包(高阶函数)作为參数传到还有一个函数中(父函数),父函数能够在子函数抛出异常时直接向上抛出异常,这时用rethrowke ...

  7. java中异常处理机制 throw抛出自定义业务逻辑异常 throws继续抛出 catch捕获后会自动继续抛向调用方法

    package com.swift; public class Exception_TestC { public static void main(String[] args) { /* * 第5题: ...

  8. java异常处理机制throw

  9. C++11异常处理 noexcept

    1.简介 在C语言中,如果程序的运行出现异常.错误,我们想提供方案处理这些异常时,我们面临许多问题,如: (1)C语言没有提供统一(标准)的方式来处理错误: (2)无法保证错误会被正确的处理: (3) ...

随机推荐

  1. python抓取网页中图片并保存到本地

    #-*-coding:utf-8-*- import os import uuid import urllib2 import cookielib '''获取文件后缀名''' def get_file ...

  2. JAVA构造函数(方法)与方法是啥意思

    成员方法必须有返回类型即使是没有返回,也要写上void 构造函数(方法)没有返回类型,而且和类名一样!一个类里面,一看就知道了譬如:public class Test{public Test(){} ...

  3. TCP的关闭,到底是几次握手,每次的标志位到底是什么!

    做题的时候遇到一个问题,TCP关闭的时候到底是三次还是四次握手,如果是三次,少了哪部分?   按照 <计算机网络> -第五版-谢希仁       然而对于TCP关闭, 有的地方能找到   ...

  4. 基于.net开发chrome核心浏览器【五】

    一:本篇将解决的问题 本章主要为了解决一下几个问题: 1.JsDialog的按钮错位的问题 我们开发出的浏览器,在有些操系统上调用alert,confirm之类的对话框时,确定和取消按钮会出现错位的情 ...

  5. Jetty使用攻略

    jetty作为一款小型的web容器用处很大,因为其小巧强大,经常作为嵌入式的组件处理http交互. Jetty 作为一个独立的 Servlet 引擎可以独立提供 Web 服务,但是它也可以与其他 We ...

  6. Stanford机器学习笔记-8. 支持向量机(SVMs)概述

    8. Support Vector Machines(SVMs) Content 8. Support Vector Machines(SVMs) 8.1 Optimization Objection ...

  7. hdu 5898 odd-even number 数位DP

    传送门:hdu 5898 odd-even number 思路:数位DP,套着数位DP的模板搞一发就可以了不过要注意前导0的处理,dp[pos][pre][status][ze] pos:当前处理的位 ...

  8. 三维网格细分算法(Catmull-Clark subdivision & Loop subdivision)附源码

    下图描述了细分的基本思想,每次细分都是在每条边上插入一个新的顶点,可以看到随着细分次数的增加,折线逐渐变成一条光滑的曲线.曲面细分需要有几何规则和拓扑规则,几何规则用于计算新顶点的位置,拓扑规则用于确 ...

  9. [No000049]狗日的中年——姜文

    文件名 大小 [No000049]狗日的中年——姜文.7z 228KB

  10. [No000014]听说不背单词,考英语会是这种下场-我们为什么必须背单词?

    由于英语对于一个程序员来说,重要性你懂得.因此我会开始逐渐在博客上加入英语的一些东西. 听说不背单词,考英语会是这种下场 在中国, 「学英语」大抵遵循着这样一条 罗蒙诺索夫质量守恒定律 因为英语学着学 ...