本文介绍了为什么在编译时不强制执行noexcept?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如你可能知道C ++ 11有noexcept关键字。现在很丑的部分是这样的:



所以这是一个委员会部分的设计失败,或者他们只是把它作为一个练习的编译作者:)在某种意义上,良好的编译器将执行它,坏的仍然可以符合? / p>

BTW如果你问为什么没有第三个选项(也不能做)的原因是我可以很容易想到一个(慢)方式检查函数是否可以抛出不。问题是离开的过程,如果你将输入限制为5和7(也就是我保证文件不包含任何除了5和7),它只会抛出,当你给它33,但这不是一个现实的问题IMHO。

解决方案

委员会很清楚地考虑了(试图)抛出异常规范不允许的异常的代码可能会被认为是错误的,并拒绝了这个想法。根据$ 15.4 / 11:



  extern void f()throw(X,Y); 

void g()throw(X){
f(); // OK
}



无论是什么促使决策,或者什么可能已经,它似乎很清楚,

移动语义可以使异常安全(特别是强保证)更难以强制执行/提供,这与C ++ 11的其他新特性(例如移动语义)的交互。当您进行复制时,如果出现问题,很容易回滚事务 - 销毁您所做的任何副本,释放内存,原始内容保持不变。



使用移动语义,这是更难的 - 如果你在移动的东西中得到一个异常,任何东西您已经移动了需要移动回到到要恢复原始订单的位置 - 但是如果移动构造函数或移动赋值运算符可以抛出,您可以获得另一个在尝试移动的东西回到尝试恢复原始对象的过程中的异常。



结合这一点,C ++ 11可以为某些类型自动生成移动构造函数和移动赋值运算符 一长串限制)。这些不一定保证不抛出异常。如果你明确写一个移动构造函数,你几乎总是想确保它不会抛出,这通常甚至很容易做(因为你通常是偷的内容,你通常只是复制一些指针 - 容易做到没有例外)。它可以得到更多的急于模板虽然,即使对于简单的例如 std:pair



这意味着,如果他们决定让 nothrow (和/或 throw())在编译时强制执行,一些未知(但可能相当大)的代码量完全崩溃 - 代码,多年来一直工作良好,突然不会编译新的编译器。



这是事实,虽然他们不是不推荐,动态异常规范保留在语言中,所以他们将在运行时执行至少一些异常规范。



因此,他们的选择:


  1. 打破大量现有代码

  2. 限制移动语义,




我怀疑任何人都喜欢这些选择,但第三个显然似乎是最后一个坏。


As you might know C++11 has noexcept keyword. Now ugly part about it is this:

http://en.cppreference.com/w/cpp/language/noexcept_spec

So is this a design failure on the committee part or they just left it as an exercise for the compile writers :) in a sense that decent compilers will enforce it, bad ones can still be compliant?

BTW if you ask why there isnt a third option ( aka cant be done) reason is that I can easily think of a (slow) way to check if function can throw or not. Problem is off course if you limit the input to 5 and 7(aka I promise the file wont contain anything beside 5 and 7) and it only throws when you give it 33, but that is not a realistic problem IMHO.

解决方案

The committee pretty clearly considered the possibility that code that (attempted to) throw an exception not allowed by an exception specification would be considered ill-formed, and rejected that idea. According to $15.4/11:

  extern void f() throw(X, Y);

  void g() throw(X) {
      f(); // OK
  }

Regardless of what prompted the decision, or what else it may have been, it seems pretty clear that this was not a result of accident or oversight.

As for why this decision was made, at least some goes back to interaction with other new features of C++11, such as move semantics.

Move semantics can make exception safety (especially the strong guarantee) much harder to enforce/provide. When you do copying, if something goes wrong, it's pretty easy to "roll back" the transaction -- destroy any copies you've made, release the memory, and the original remains intact. Only if/when the copy succeeds, you destroy the original.

With move semantics, this is harder -- if you get an exception in the middle of moving things, anything you've already moved needs to be moved back to where it was to restore the original to order -- but if the move constructor or move assignment operator can throw, you could get another exception in the process of trying to move things back to try to restore the original object.

Combine this with the fact that C++11 can/does generate move constructors and move assignment operators automatically for some types (though there is a long list of restrictions). These don't necessarily guarantee against throwing an exception. If you're explicitly writing a move constructor, you almost always want to ensure against it throwing, and that's usually even pretty easy to do (since you're normally "stealing" content, you're typically just copying a few pointers -- easy to do without exceptions). It can get a lot harder in a hurry for template though, even for simple ones like std:pair. A pair of something that can be moved with something that needs to be copied becomes difficult to handle well.

That meant, if they'd decided to make nothrow (and/or throw()) enforced at compile time, some unknown (but probably pretty large) amount of code would have been completely broken -- code that had been working fine for years suddenly wouldn't even compile with the new compiler.

Along with this was the fact that, although they're not deprecated, dynamic exception specifications remain in the language, so they were going to end up enforcing at least some exception specifications at run-time anyway.

So, their choices were:

  1. Break a lot of existing code
  2. Restrict move semantics so they'd apply to far less code
  3. Continue (as in C++03) to enforce exception specifications at run time.

I doubt anybody liked any of these choices, but the third apparently seemed the last bad.

这篇关于为什么在编译时不强制执行noexcept?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 07:41
查看更多