【C++详解】C++异常处理 | 异常规格说明符

前言

noexcept关键字是仅用于C++的异常处理关键字。

上一篇中,我们认识了异常的抛出、捕捉及重载。不妨想想以下问题:

  • 如果有一个函数(可能来自第三方库)会抛出异常,怎么知道它可能抛出的类型呢?
    查看源代码确实是一种方式,但如果函数体很长,或函数嵌套函数呢?
    如果第三方库函数只有函数声明,没有函数实现呢?

这就来到了今天的主题——异常规格说明符


何为异常规格说明?

异常规格说明,是用于说明函数可能抛出的异常种类,作为函数声明的修饰符,跟在参数列表【()】后面,与静态函数说明const1放在一起。

语法

它的标准语法为:

[adding] ret-type func-name( list ) [adding] throw( exception ) ;

其中,throw()前是一般的函数声明(或实现),throw里写数据类型,表示函数可能抛出的异常,如:

void func1() throw();						//表示不抛出任何异常
void func2() throw(int);					//可能抛出int型异常
void func3() throw(const char * , float);	//可能抛出C风字符串和单精浮点型异常
void func4() throw(thread);					//可能抛出thread对象异常

可以看出,throw()里不写任何类型表示该函数不抛出任何异常。

意义

  1. 有了异常规格说明,当需要了解函数异常时,只需打开声明就一目了然了。
  2. 维护者不应抛出任何说明符之外的异常类型。
  3. 说明符是函数接口的一部分,用于说明函数如何正确使用。

规格说明之外的异常

考虑以下代码:

void func() throw(int){
	throw 'x';//与异常规格说明不符
}
int main(){
	try{
		func();
	}
	catch(int e){
		cout<<"exception in int!\n";
	}
	catch(char e){
		cout<<"exception in char!\n";
	}
	return 0;
}

编译器会作何反应?下面罗列了不符编译器的反应。

  • BCC:
    Abnormal program termination
    
  • g++:
    terminate called after throwing an instance of 'char'
    
  • VS2019、VC:
    exception in char!
    
  • 多数线上编译器:
    warning: dynamic exception specifications are deprecated in C++11 [-Wdeprecated]
        3 | void func() throw(int)
          |             ^~~~~
    terminate called after throwing an instance of 'char'
    Aborted (core dumped)
    

可以看到,除了VS、VC,大部分编译器会直接拒绝非规格说明的异常抛出。因为这是C++11规范。



noexcept关键字

注:noexcept关键字仅可用于C++。

该关键字于C++11加入,用于替代throw()说明符。表示函数不会抛出任何异常。
它的标准形式为:

ret-type func_name( [params] ) [adding...] noexcept( noexcept(exception) )

第一个noexcept后的()中是一个布尔表达式,表示当且仅当布尔值为真时该函数是noexcept的(即它是throw()的)。
第一个noexcept后的(...)可以省略,相当于noexcept(true)。(表示任何时候都不会抛出异常)

第二个noexcept(…)类似于一个函数,其参数必须为函数执行语句(带括号,形如func()),表示检查该该函数是否抛出异常。
以下函数声明表示当且仅当funcc()不抛出异常时func()也不抛出异常2

void func() noexcept( noexcept(funcc()) );

异常的传递性

使用除VC、VS以外的编译器执行以下程序(因为VC、VS不遵守C++11异常规范):

#include<iostream>
using namespace std;

void funcc(){
	throw 114514;
}

void func() noexcept//不会抛出异常
{
	funcc();//在另一个函数中抛出异常
}

int main(){
	try{
		func();
	}
	catch(int err){
		cerr<<"exception!\n";
	}
	return 0;
}
terminate called after throwing an instance of 'int'
Aborted (core dumped)

不难看出,异常是传递的,一个函数是noexcept的,当且仅当它的函数主体、所调用的函数、方法都不抛出异常。即使是在调用的函数中抛出异常,也不是noexcept。
将以上程序改为:

#include<iostream>
using namespace std;

void funcc(){
	throw 114514;
}

void func() 
/* [-] *///noexcept
/* [+] */  noexcept( noexcept(funcc()) )
{
	funcc();
}

int main(){
	try{
		func();
	}
	catch(int err){
		cerr<<"exception!\n";
	}
	return 0;
}
#(正常运行)
exception!





@HaohaoCppDebuger|寻兰 
2021/12/21 

-----THE END-----
THANK YOU !


更多文章


  1. 静态函数说明,在函数主体{}前(或声明结束;前)的修饰符,表示该函数无法修改变量。 ↩︎

  2. 有两种可能:
    1.func()调用了funcc(),而funcc()可能抛出异常,就相当于一个抛出异常白名单。
    2.func()功能包含(或被包含、或类似于)funcc(),因此,只要funcc()不出错,func()一定没问题,即两者是不相关的函数。 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值