C++11:为何引入noexcept替代throw
admin
2024-03-14 17:00:42
0

引言

noexcept是C++11新引入的异常关键字。noexcept既是说明符,也是运算符。作为说明符,它的作用是指定函数是否抛出异常;作为运算符,它的作用是编译时检查,如果表达式不会抛出任何异常则返回 true,否则返回false。

noexcept说明符

noexcept说明符的语法格式:

noexcept  // noexcept 等价于noexcept(true)
noexcept(expression) // expression可转换为bool的常量表达式,expression为true表示函数不会抛出异常
throw() // C++11 deprecated,C++20 removed throw()等价于noexcept(true)

noexcept(false)表示允许抛出异常;noexcept(true) 表示不允许抛出异常,noexcept与noexcept(true)等价;标记了noexcept(true) 或noexcept的函数如果抛出异常了,那么std::terminate()将会调用并结束进程。

C++11规定,满足下述条件的函数允许抛出异常:

  • 使用throw声明异常,除throw()外其他形式均允许抛出异常,例如,int func() throw(int)允许抛出异常,而int func() throw()不允许抛出异常。
  • noexcept(expression)中expression求值为false的函数。例如:void f() noexcept(false)允许抛出异常。
  • 函数声明中没有noexcept说明符的函数,例如:void g() 允许抛出异常。

同时C++11也规定,满足下述条件的函数不允许抛出异常:

  • 析构函数(如果基类或成员允许抛出异常,析构函数会转为允许抛出异常)
  • 隐式声明(或=default)的默认构造函数,拷贝构造函数,移动构造函数(如果基类同名函数或成员允许抛出异常,此函数会转换为抛出异常)
  • 隐式声明(或=default)的拷贝赋值运算符,移动赋值运算符
  • operator delete, operator delete[]

除此之外,需要特别注意的是noexcept(expression) 中的expression必须编译期间可求值,编译器最终会将expression 的结果转换为 true 或false再传递给 noexcept(),因而可以认为noexcept(expression) 是被转换为 noexcept(true) 或 noexcept(false) 作用于函数声明。

C++17之前的标准中,noexcept说明符和throw是函数签名的一部分,但是C++17之后的标准规定中,noexcept说明符不是函数签名的一部分。

noexcept运算符

noexcept 运算符会在编译时检查,如果表达式不会抛出任何异常则返回 true。它亦可用于函数模板的 noexcept 说明符中;noexcept运算符的语法格式:

noexcept(expression)

noexcept(expression)返回bool型纯右值。noexcept 运算符会在编译时检查,编译期不会对expression表达式进行求值。如果expression的潜在异常集合为空,noexcept(expression)会求值为true,否则noexcept(expression)求值为false。

#include 
#include 
#include void mayThrow();
void noThrow() noexcept;
auto layThrow = []{};
auto lnoThrow = []() noexcept {};class T
{
public:~T(){} 
};class U
{
public:~U(){}std::vector v;
};class V
{
public:std::vector v;
};int main()
{T t;U u;V v;std::cout << std::boolalpha<< "mayThrow() 可能会抛出异常吗?" << !noexcept(mayThrow()) << '\n'<< "noThrow() 可能会抛出异常吗?" << !noexcept(noThrow()) << '\n'<< "lmayThrow() 可能会抛出异常吗?" << !noexcept(lmayThrow()) << '\n'<< "lnoThrow() 可能会抛出异常吗?" << !noexcept(lnoThrow()) << '\n'<< "~T() 可能会抛出异常吗?" << !noexcept(std::declval().~T()) << '\n'<< "T(T 右值) 可能会抛出异常吗?" << !noexcept(T(std::declval())) << '\n'<< "T(T 左值) 可能会抛出异常吗?" << !noexcept(T(t)) << '\n'<< "U(U 右值) 可能会抛出异常吗?" << !noexcept(U(std::declval())) << '\n'<< "U(U 左值) 可能会抛出异常吗?" << !noexcept(U(u)) << '\n'  << "V(V 右值) 可能会抛出异常吗?" << !noexcept(V(std::declval())) << '\n'<< "V(V 左值) 可能会抛出异常吗?" << !noexcept(V(v)) << '\n';  
}

输出:

mayThrow() 可能会抛出异常吗?true
noThrow() 可能会抛出异常吗?false
lmayThrow() 可能会抛出异常吗?true
lnoThrow() 可能会抛出异常吗?false
~T() 可能会抛出异常吗?false
T(T 右值) 可能会抛出异常吗?false
T(T 左值) 可能会抛出异常吗?false
U(U 右值) 可能会抛出异常吗?true
U(U 左值) 可能会抛出异常吗?true
V(V 右值) 可能会抛出异常吗?false
V(V 左值) 可能会抛出异常吗?true

noexcept的优势

与C++98中的throw相对比,noexcept会给我们带来许多优势。

改善程序执行效率

如果你的程序不允许抛出异常,请声明为noexcept。编译在编程链接生成可执行程序时,如果一个函数运行抛出异常,编译器会默认值在函数末尾添加异常处理相关函数代码段,这个代码函数名称一般较unwinding,所以也称unwinding stack。stackoverflow技术网站的有详细的性能评估。大家可以参考此wiki:https://stackoverflow.com/questions/26079903/noexcept-stack-unwinding-and-performance

noexcept可捕获更多异常

noexcept可处理以前throw无法捕获的异常,例如

struct
{void CreateOtherClass() { T t{}; }
};

CreateOtherClass是否抛出异常将由T的构造函数决定,我们可以通过这种方式实现。

struct
{void CreateOtherClass() noexcept(is_nothrow_default_constructible::value) { T t{}; }
};

但是这个throw是无法做到的。

noexcept与throw结束异常方式不同

throw声明函数,如果抛出异常std::unexpected()将会被调用并结束进程。noexcept声明的函数,如果抛出异常std::terminate()将会调用并结束进程。

总结

做为C++11新引入的关键字,noexcept既是说明符,也是运算符。作为说明符,它的作用是指定函数是否抛出异常;作为运算符,它的作用是编译时检查,表达式不会抛出任何异常则返回 true,否则返回false。
一般情况下如果函数不会抛出异常最好添加noexcept说明符,这样可以提升函数执行效率,而且优先使用noexcept替代throw。

相关内容

热门资讯

怎么解除订阅安卓系统,安卓系统... 你是不是也和我一样,手机里订阅了好多服务,结果现在想解除订阅,却一头雾水?别急,今天就来手把手教你如...
安卓系统停用怎么开启,轻松恢复... 亲爱的手机控们,你是否曾经遇到过安卓系统突然停用的情况,让你手忙脚乱,不知所措?别担心,今天就来教你...
安卓系统电池健康度,电池健康度... 你有没有发现,你的安卓手机最近是不是有点儿不给力了?电池续航能力大不如前,充电速度也慢了不少?别急,...
安卓系统按键怎么截图,安卓系统... 你是不是也和我一样,有时候想截个图分享给朋友,却发现安卓手机的截图功能有点神秘呢?别急,今天就来手把...
购票系统安卓源代码,架构设计与... 你有没有想过,那些我们每天离不开的购票系统,它们背后的秘密是什么呢?今天,就让我带你一探究竟,揭开购...
安卓手机系统后台测试,深度解析... 你有没有发现,你的安卓手机后台总是悄悄地忙碌着?别小看了这些后台程序,它们可是手机系统稳定运行的关键...
安卓系统重启的图标,解锁设备新... 手机突然重启,是不是心里有点慌?别急,今天就来和你聊聊安卓系统重启的图标,让你一眼就能认出它,再也不...
车载智慧屏安卓系统,智能出行新... 你有没有发现,现在的车载智慧屏越来越智能了?尤其是那些搭载了安卓系统的,简直就像是个移动的小电脑,不...
安卓系统连上网权限,解锁设备无... 你有没有发现,你的安卓手机里有些应用总是偷偷连上网?别小看这个小小的网络权限,它可是能影响你隐私、消...
安卓谷歌操作系统,探索安卓谷歌... 你知道吗?在智能手机的世界里,有一个操作系统可是无人不知、无人不晓,那就是安卓谷歌操作系统。它就像一...
安卓系统手写%怎样调出,具体实... 你有没有遇到过这种情况:在使用安卓手机的时候,突然想用手写输入法来记录一些灵感或者重要信息,可是怎么...
安卓手机重置 系统设置,轻松恢... 手机用久了是不是感觉卡顿得厉害?别急,今天就来教你怎么给安卓手机来个大变身——重置系统设置!想象你的...
win如何安装安卓系统,Win... 哇,你有没有想过,让你的Win系统也能玩转安卓应用?没错,就是那种在手机上轻松自如的安卓系统,现在也...
苹果qq和安卓系统,跨平台体验... 你有没有发现,现在手机市场上,苹果和安卓的较量可是越来越激烈了呢!咱们就来聊聊这个话题,看看苹果QQ...
显示最好的安卓系统,探索最新旗... 你有没有想过,为什么安卓系统那么受欢迎呢?它就像一个魔法盒子,里面装满了各种神奇的魔法。今天,就让我...
安卓app怎么降级系统,系统版... 你有没有发现,有时候安卓手机的系统更新后,新功能虽然炫酷,但老系统用起来更顺手呢?别急,今天就来教你...
雷军脱离安卓系统,引领科技变革... 你知道吗?最近科技圈可是炸开了锅,因为我们的雷军大大竟然宣布要脱离安卓系统,这可真是让人大跌眼镜啊!...
安卓系统自动开网络,安卓系统自... 你有没有发现,手机里的安卓系统有时候会自动开启网络连接,这可真是让人又爱又恨啊!有时候,你正专心致志...
安卓系统怎样控制后台,因为服务... 手机里的安卓系统是不是感觉越来越卡了?后台程序太多,不仅耗电还影响性能。别急,今天就来教你怎么巧妙地...
安卓系统打游戏推荐,一触即达! 你有没有发现,现在手机游戏越来越好玩了?不管是休闲小游戏还是大型MMORPG,都能在手机上畅玩。但是...