noexcept说明

在C++11之后,表示函数不会抛出异常的动态异常声明throw()被新的noexcept异常声明所取代。
该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化。
如果在运行时,noexecpt函数向外抛出了异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。

从语法上讲,noexcept修饰符有两种形式,一种就是简单地在函数声明后加上noexcept关键字。比如:

void excpt_func() noexcept;

另外一种则可以接受一个常量表达式作为参数,如下所示:

void excpt_func() noexcept (常量表达式);

抛出异常与栈展开(stack unwinding)

抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常。如果不能处理,就退出当前函数,并且释放当前函数的内存并销毁局部对象,继续到上层的调用函数中查找,直到找到一个可以处理该异常的catch。这个过程称为栈展开(stack unwinding)。当处理该异常的catch结束之后,紧接着该catch之后的点继续执行。

  1. 为局部对象调用析构函数

如上所述,在栈展开的过程中,会释放局部对象所占用的内存并运行类类型局部对象的析构函数。但需要注意的是,如果一个块通过new动态分配内存,并且在释放该资源之前发生异常,该块因异常而退出,那么在栈展开期间不会释放该资源,编译器不会删除该指针,这样就会造成内存泄露。

  1. 析构函数应该从不抛出异常

在为某个异常进行栈展开的时候,析构函数如果又抛出自己的未经处理的另一个异常,将会导致调用标准库terminate函数。通常terminate函数将调用abort函数,导致程序的非正常退出。所以析构函数应该从不抛出异常。

  1. 异常与构造函数

如果在构造函数对象时发生异常,此时该对象可能只是被部分构造,要保证能够适当的撤销这些已构造的成员。

  1. 未捕获的异常将会终止程序

不能不处理异常。如果找不到匹配的catch,程序就会调用库函数terminate。

验证

#include <iostream>
using namespace std;struct A {A()  { cout << "constructor" << endl; }~A() { cout << "destructor" << endl; }
};void func1() noexcept
{A a1;A a2;
}void func2()
{A a1;A a2;
}int main()
{func1();func2();return 0;
}# gcc -std=c++11
(gdb) disassemble func1
(gdb) disassemble func2

可以看出加了noexcept的函数没有增加_Unwind_Resume调用,汇编代码更短小,为编译优化增加更多可能。

什么时候该使用noexcept

使用noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。然而,并不是加上noexcept就能提高效率,步子迈大了也容易扯着蛋。
以下情形鼓励使用noexcept:

  • 移动构造函数(move constructor)

  • 移动分配函数(move assignment)

  • 析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。

  • 叶子函数(Leaf Function)。叶子函数是指在函数内部不分配栈空间,也不调用其它函数,也不存储非易失性寄存器,也不处理异常。
    最后强调一句,在不是以上情况或者没把握的情况下,不要轻易使用noexception。

  • 每个函数都考虑noexcept会很麻烦,所以只在明显的时候使用

  • 现在编译器在好路径上异常没有影响,noexcept可能的作用是减小体积

  • 推荐在构造、复制等常用操作标记noexcept,这样性能提升可能会比较大。例如vector不会使用你的类move操作,除非它被标记为noexcept(有的编译器能自动推导)

  • noexcept主要是给使用者看的,对编译器影响不大

异常说明与指针、虚函数和拷贝控制

  1. 函数指针及该指针指向的函数必须具有一致的异常说明。如果一个指针做出了不抛出异常的声明,则该指针将只能指向不抛出异常的函数。
  2. 如果显示或隐式说明了指针可能抛出异常,那么该指针可以指向任何函数。
  3. 如果一个虚函数承诺不会抛出异常,则后续派生出来的衍生类的虚函数也必须做出同样的承诺。反之则不需要。
  4. 当编译器合成拷贝控制成员的时候,也会生成一个异常说明。如果对所有成员和基类的所有操作都承诺了不抛出异常,则合成的成员是noexcept的;如果有任意一个函数可能抛出异常,则合成的成员是noexcept(false)。

参考

http://liubigbin.github.io/2016/07/06/C-11%E5%B8%B8%E8%A7%84%E7%89%B9%E6%80%A7%E4%B9%8Bnoexcept/
https://www.jianshu.com/p/08a53d8c9670
https://www.cnblogs.com/zhuyf87/archive/2012/12/23/2829725.html
https://www.cnblogs.com/catch/p/3604516.html
https://www.cnblogs.com/catch/p/3619379.html
https://www.cnblogs.com/sword03/p/10020344.html
https://www.zhihu.com/question/30950837
https://stackoverflow.com/questions/10787766/when-should-i-really-use-noexcept

noexcept与栈展开(stack unwinding)相关推荐

  1. 栈展开(stack unwinding)

    栈展开(stack unwinding)的定义 抛出异常时,将暂停当前函数的执行,开始查找匹配的 catch 子句.首先检查 throw 本身是否在 try 块内部,如果是,检查与该 try 相关的 ...

  2. c++抛出异常与栈展开(stack unwinding)

    抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句.首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常.如果不能处理,就退出当前函数 ...

  3. 栈展开(stack unwinding)在destructors中的exceptions

    抛出异常与栈展开(stack unwinding) 抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句.首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句 ...

  4. 抛出异常与栈展开(stack unwinding)

    抛出异常时,将暂停当前函数的执行,开始查找匹配的catch子句.首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否可以处理该异常.如果不能处理,就退出当前函数 ...

  5. C++ 栈展开如何防止内存泄露

    在栈展开(stack unwinding)是指,如果在一个函数内部抛出异常,而此异常并未在该函数内部被捕捉,就将导致该函数的运行在抛出异常处结束,所有已经分配在栈上的局部变量都要被释放.如果被释放的变 ...

  6. 堆(heap)与栈(stack)的区别(一)

    堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收,但它与数据结构中的堆不是一回事,分配方式类似于链表. 栈(stack):由编译器自动分配和释放,存函数的参数值, ...

  7. Java异常的栈轨迹(Stack Trace)

    捕获到异常时,往往需要进行一些处理.比较简单直接的方式就是打印异常栈轨迹Stack Trace.说起栈轨迹,可能很多人和我一样,第一反应就是printStackTrace()方法.其实除了这个方法,还 ...

  8. 编写代码,实现一个栈(Stack)的类。

    编写代码,实现一个栈(Stack)的类. 栈是只能在一端插入和删除数据的序列.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被 ...

  9. 【编程】堆(heap)和栈(stack)的区别

    从C/C++的内存分配(与操作系统相关)上来说,堆(heap),栈(stack)属于内存空间的一段区域. 效率: 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持(有专门的寄存器存放栈的地址,压 ...

最新文章

  1. springboot默认开启事务吗_香~Spring Boot 应用也可以有配置中心。
  2. 如何解决 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0” 提供程序
  3. C++ code:数值计算之矩形法求解积分问题
  4. 【Linux】一步一步学Linux——indent命令(262)
  5. 软件设计中的抽象层次
  6. python工具栏消失_[Python自学] PyQT5-菜单栏、工具栏、状态栏
  7. 使用的 SQL Server 版本不支持数据类型“datetime2”的错误解决方法
  8. 【渝粤教育】广东开放大学 社会调查与方法 形成性考核 (35)
  9. 重庆邮电计算机科学分数线,2020重庆邮电大学录取分数线已公布
  10. java_web用户的自动登录模块的实现
  11. 第 22 章 Beta
  12. 批量生产insert 或者update语句
  13. JAVA进行文档转换_基于JAVA实现由Word文档向LaTeX文档转换的方法及系统与流程
  14. Kali [masscan]端口扫描
  15. 三菱PLC编程语言的特点
  16. MFC TabCtrl 控件修改标签尺寸
  17. html5 lang属性都有哪些语言,HTML5中的lang属性,zh
  18. 新中国首位MIT计算机博士高光荣教授逝世,美团创始人王兴曾是他的学生
  19. 英文中常见连读规律总结
  20. matlab 纯迟延_DMC算法MATLAB编程及仿真

热门文章

  1. java js方法_JAVA调用js方法
  2. 对于团队的一些感悟感想
  3. ## Overlay 是什么
  4. Calendar判断指定时间是周几、上下午、月份的简单运用
  5. excel行列值相同,交叉单元格高亮显示
  6. 如何修改excel的修改日期?
  7. Java高并发程序设计入门
  8. 【C++】setw()函数
  9. dnf最新地图编号2020_dnf2020搬砖地图排行榜 dnf2020最佳搬砖地图
  10. 应用层协议的捕获和解析