文档章节

Effective C++: exception

SHIHUAMarryMe
 SHIHUAMarryMe
发布于 2017/03/26 21:04
字数 1189
阅读 27
收藏 0

1), 异常机制概述:

异常处理是C++的一项语言机制,用于在程序中处理异常事件。异常事件在C++中表示为异常对象。异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统为程序设置当前异常对象,然后执行程序的当前异常处理代码块,在包含了异常出现点的最内层的try块,依次匹配catch语句中的异常对象(只进行类型匹配,catch参数有时在catch语句中并不会使用到)。若匹配成功,则执行catch块内的异常处理语句,然后接着执行 try...catch... 块之后的代码。如果在当前的 try...catch... 块内找不到匹配该异常对象的catch语句,则由更外层的 try...catch... 块来处理该异常;如果当前函数内所有的try...catch... 块都不能匹配该异常,则递归回退到调用栈的上一层去处理该异常。如果一直退到主函数main()都不能处理该异常,则调用系统函数 terminate() 终止程序(调用terminate()的结果就是不会stack unwinding)。
 

demo1:

int main()
{
    int score=0;
    while (cin >> score)
    {
        try
        {
            if (score > 100 || score < 0)
            {
                throw score;
            }
            //将分数写入文件或进行其他操作
        }
        catch (int score)
        {
            cerr << "你输入的分数数值有问题,请重新输入!";
            continue;
        }
    }

    return 0;
}

 

2) throw关键字

throw;

throw expression;

throw: 一般用于catch捕获异常以后重新抛出异常给上层调用捕获.

throw expression: 一般用于try语句块内抛出一个异常.

 

3) try-catch与RAII

demo2:

#include <iostream>

struct Test {
	Test() { std::cout << "default - constructor" << std::endl; }
	Test(const Test& other) { std::cout << "copy - constructor" << std::endl; }
	Test& operator=(const Test& other) { std::cout << "operator = " << std::endl; }
	~Test() { std::cout << "destroy" << std::endl; } 
};

int main()
{
	try {
		Test t; //默认构造函数.
		throw t; //调用Test的拷贝构造函数,拷贝一份t到存储异常的专用内存中(不是堆栈).

		//try{}结束的时候会调用t的析构函数.
	}catch (Test t1){ //从存放异常的专用内存中拷贝一份到t1
		std::cout << "-------------" << std::endl;

		//catch{}结束释放专用内存的Test
		//释放t1.
	}
	std::cout << "------------------" << std::endl;

	return 0;
}

 

4) catch(exception){}

catch用于匹配被throw的exception对象,catch在匹配的时候也遵循:

1, copy(construct)

2, move(construct)

3, reference(引用)

4, copy elision

5, 面对对象(派生类向基类转换),以及{}块内的virtual function的动态调用.

6, 允许函数被转换为指向函数的指针.

7, 允许数组转为指针.

但是catch匹配异常的原则却跟函数匹配参数的原则是不一样的:

寻找catch语句的过程中,匹配上的未必是类型完全匹配那项,而在是最靠前的第一个匹配上的catch语句(我称它为最先匹配原则)。所以,派生类的处理代码catch语句应该放在基类的处理catch语句之前,否则先匹配上的总是参数类型为基类的catch语句,而能够精确匹配的catch语句却不能够被匹配上。

使用catch(...){}可以捕获所有类型的异常,根据最先匹配原则,catch(...){}应该放在所有catch语句的最后面,否则无法让其他可以精确匹配的catch语句得到匹配。通常在catch(...){}语句中执行当前可以做的处理,然后再重新抛出异常。注意,catch中重新抛出的异常只能被外层的catch语句捕获。

当然了我们也可以不处理rethrow exception:

catch(exception){
 //do something
throw;
}

 

5) function-try-block

function-try-block一般用于构造函数,当在构造一个class/struct对象的成员的时候有exception被throw了,这个时候我们可以通过该机制来log,同时该机制会造成stack unwinding.

也就是说如果一个class/struct在构造member data的时候throw了异常,那么会调用已构造的member data的析构函数,或者已构造的父类的析构函数,然后会rethrow该异常.

 

demo3:

#include <iostream>
#include <stdexcept>
 
struct A {
    int n;
    A(int n = 0): n(n) { std::cout << "A(" << n << ") constructed successfully\n"; }
    ~A() { std::cout << "A(" << n << ") destroyed\n"; }
};
 
int foo()
{
    throw std::runtime_error("error");
}
 
struct B {
    A a1, a2, a3;
    B() try : a1(1), a2(foo()), a3(3) {
        std::cout << "B constructed successfully\n";
    } catch(...) {
    	std::cout << "B::B() exiting with exception\n";
        //throw;  //notice that
    }
    ~B() { std::cout << "B destroyed\n"; }
};
 
struct C : A, B {
    C() try {
        std::cout << "C::C() completed successfully\n";
    } catch(...) {
        std::cout << "C::C() exiting with exception\n";
        //throw; //notice that
    }
    ~C() { std::cout << "C destroyed\n"; }
};
 
int main () try
{
    // creates the A base subobject
    // creates the a1 member of B
    // fails to create the a2 member of B
    // unwinding destroys the a1 member of B
    // unwinding destroys the A base subobject
    C c;
} catch (const std::exception& e) {
    std::cout << "main() failed to create C with: " << e.what();
}

 

 

© 著作权归作者所有

SHIHUAMarryMe
粉丝 13
博文 162
码字总数 138435
作品 0
武汉
程序员
私信 提问
C++各阶段学习书目

1. 入门 Lippman的《Essential C++》 顾名思义,这本书是很短小精悍的。通过这本书,可以对C++的最常用和重要的特性有全面的了解,并对C++的全貌有一个概念。虽然这远远不够,但就是这样的书...

晨曦之光
2012/04/24
509
1
一个典型的 C++ 程序员成长经历

1. 完整的学一遍 C++ 所有语言特性,典型书籍 "The C++ Programming Language" Part1, Part2, "C++ Primer" 感觉 C++ 像大杂烩(多编程范型),各种精妙的语法特性 (friend, virtual/RTTI, c......

晨曦之光
2012/05/16
547
0
001-EMC 深入解读-目录

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1007729991/article/details/82717008 除了刚毕业的应届生,从来没人敢说他精通 C++,Bjarne Stroustrup (C...

--Allen--
2018/09/15
0
0
典型的 C++ 程序员成长经历

一个典型的 C++ 程序员成长经历: 1. 完整的学一遍 C++ 所有语言特性,典型书籍 "The C++ Programming Language" Part1, Part2, "C++ Primer" 感觉 C++ 像大杂烩(多编程范型),各种精妙的语......

晨曦之光
2012/05/23
329
0
C#转C++的一点分享

从C#转C++有段时间了,一直想分享点什么,但又不太好意思分享,毕竟自己做C++的时间不太长,最近感觉自己已能胜任现有工作,想分享的想法又强了点,前几天看到这样一篇博客《那些年·我们读过的专业...

爱情经纬线
2014/01/17
4.1K
11

没有更多内容

加载失败,请刷新页面

加载更多

kibana汉化

kibana5 / 6 需要下载补丁包,https://github.com/anbai-inc/Kibana_Hanization 其中 v6 版本原生支持国际化,只需要添加资源文件并且配置即可 kibana7 v7版本官方内置汉化资源,在配置文件 ...

细肉云吞
26分钟前
5
0
spring boot 自定义日志 log4j2

使用默认的日志在实际开发中会存在很多问题,比如备份文件名称无法自动重命名、各个等级的日志被放在一个文件中等,所以实际开发中为了更好满足我们的需求,我们一般都会自定义采用配置的方式...

雷开你的门
30分钟前
7
0
PCB设计-Allegro软件入门系列-设计参数配置(上)

前言 经历了导入网表,和放置器件后,我们就要画板子了,但是必要的设计参数也要先准备好,磨刀不误砍柴工。 《一》显示参数 这里主要设置DRC报错标志大小和飞线显示类型 (1)DRC标志可以适当...

demyar
31分钟前
7
0
js实现微博、微信分享

html <!-- 分享 --><div class="share-box"> <b style="vertical-align: middle;">分享到:</b> <a title="分享到新浪微博" class="shareSina"><span class="share-icon"></span><......

张兴华ZHero
47分钟前
7
0
创龙TMS320DM8168浮点DSP C674x + ARM Cortex-A8的CPU、NAND FLASH、NOR FLASH

TL6678-EasyEVM是广州创龙基于SOM-TL6678核心板而研发的一款多核高性能DSP开发板。开发板采用核心板+底板方式,底板采用沉金无铅工艺的四层板设计,尺寸为200mm*106.65mm,它为用户提供了SOM...

Tronlong创龙
50分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部