C/C++ 11 “noexcept” 关键字的作用

关于 “noexcept” 关键字的使用,C/C++ 开发人员用的不多,常见的用法是在写 FCL(框架类库)及 BCL(基础类库)上用的多一点。

在 C/C++ 11 以前大家是用 “throw()” 来声明的,当然进入到 C/C++ 11 之后人们应首选采用关键字 “noexcept” 来描述函数潜在的异常抛出。

noexcept 关键字的作用跟 throw() 的作用差不多,就是标记声明当前函数可能存在 “抛出异常” 的行为。

参考:

noexcept(true) 函数不会抛出异常

noexcept(false) 函数会抛出异常(函数未声明则默认为该规则)

throw() 函数不会抛出异常

throw(int) 函数会抛出 int 类型的异常

throw(int, std::string) 函数会抛出 int、std::string 类型的异常

例如:

其它开发人员如何知道调用的某个 C/C++ 函数内部实现,是否存在异常的情况? 如果人们不显示为函数标记一下,那么该函数发生异常时,调用方没有对异常(结构化异常)进行处理,那么导致的结果就是程式崩溃,对于服务器这类追求 7*24、30*24、365*24 小时不出现任何故障的程序而言,毫无疑问是潜在巨大的风险挑战。

这是早前 throw() 关键字的作用,但到达 C++ 11 时代,开发人员采用 noexcept 关键字可以相对更灵活的控制,某个函数是否编译关于结构化异常处理的代码。

例如:

当人们为函数声明 noexcept(true) = noexcept 时,则该函数内不允许抛出异常且 C/C++ 编译器不处理关于结构化异常相关的编译器实现代码,可以相对的优化程序编译后的总体大小,但不意味着 noexcept(false) 声明的函数无法调用 “需要抛出异常的函数”,这两者之间不冲突,noexcept(false) 仅仅只是意味着,该函数自身实现不会抛出异常。

而且一个好的编码建议,C/C++ 开发人员应当严格遵循 C/C++ 结构化异常处理的规范,不需要抛出异常的函数都必须明确声明,抛出异常的函数都应只抛出派生在 std::exception 下的类型,而不是各种数值结构体类型都来了,这不仅仅是为了减少 C/C++ 编译后程序的体积,更是代码可读性及执行效能的一种优化。

throw(...) 关键字声明在未来的 C/C++ 语言标准中,或被标准委员会移除【Obsolete】,所以人们应当在确保工程边界的情况下有限度的使用该关键字用于 C/C++ 结构化异常处理。

以VC++为例子:

我们知道 C/C++ 结构化异常的实现是通过 “串联数组链表” 实现的,该链表根由操作系统提供,当函数发生异常时(CPU发出中断信号)操作系统会把当前的EIP位置修正到结构化异常处理器链表上面,是一个迭代的结构从链顶部逐个查找匹配的异常处理器(Exception Handler)而 C/C++ 编译器实现的对于某个具体类型感兴趣 when case 是由 C/C++ 编译器结合类型系统来实现的。

Linux 平台上面对于异常的处理是通过操作系统内核发出的异常信号来处理的,当发生异常就会设置当前EIP切换到信号处理器(signal handler)上面,但 Linux 平台C/C++程序的异常处理并非是基于信号机制,而是编译器自行实现的一套,故而该异常处理机制存在相对明确的捕获边界。

下面在一个简单函数上声明 noexcept 与不声明会不会有质的区别!

代码:

int add(int x, int y) { return x+y; }

int add_noexcept(int x, int y) noexcept { return x+y; }

汇编:

_x$ = 8                                       ; size = 4
_y$ = 12                                                ; size = 4
int add(int,int) PROC                                  ; add
        push    ebp
        mov     ebp, esp
        mov     eax, DWORD PTR _x$[ebp]
        add     eax, DWORD PTR _y$[ebp]
        pop     ebp
        ret     0
int add(int,int) ENDP                                  ; add

_x$ = 8                                       ; size = 4
_y$ = 12                                                ; size = 4
int add_noexcept(int,int) PROC                   ; add_noexcept
        push    ebp
        mov     ebp, esp
        mov     eax, DWORD PTR _x$[ebp]
        add     eax, DWORD PTR _y$[ebp]
        pop     ebp
        ret     0
int add_noexcept(int,int) ENDP                   ; add_noexcept

上述两个编译的汇编代码从结果上来说是没有区别的,这是因为两个 add 函数内部实现并不涉及结构化异常的一些处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值