今天我了解到swap不允许在C++中抛出异常.
我也知道以下内容也不能抛出异常:
还有其他人吗?
或许,是否有某种列表提到可能不会抛出的一切?
(显然,比标准本身更简洁.)
Dav*_*eas 17
不能和不应该有很大的区别.原始类型的操作不能抛出许多函数和成员函数,包括标准库和/或许多其他库中的许多操作.
现在不应该,你可以包括析构函数和交换.根据你实现它们的方式,它们实际上可以抛出,但你应该避免使用抛出的析构函数,并且在swap提供无抛出保证的交换操作的情况下,是在类中实现强大的异常保证的最简单方法,您可以复制到一边,对副本执行操作,然后与原始文件交换.
但请注意,该语言允许析构函数和swap抛出.swap 可以扔了,在最简单的情况下,如果你不超载,然后std::swap进行复制建造,分配和破坏,三个操作可在每个抛出一个异常(取决于你的类型).
在C++ 11中,析构函数的规则发生了变化,这意味着没有异常规范的析构函数具有隐式noexcept规范,这反过来意味着如果它抛出异常,运行时将调用terminate,但是您可以将异常规范更改为noexcept(false)然后析构函数也可以抛出.
在一天结束时,如果不了解代码库,就无法提供异常保证,因为C++中的每个函数都可以抛出.
所以,这并不完全回答你的问题-我搜索了一下从我自己的好奇心-但我认为这 不抛出保证功能/经营者大多来自在C语言中的任何C风格的函数++以及一些功能源于其任意简单,足以提供这样的保证.一般来说,C++程序不应该提供这种保证(什么时候应该使用std :: nothrow?)并且甚至不清楚这样的保证是否会在经常使用异常的代码中为您提供任何有用的保证.我找不到一个全面的所有C++函数列表,这些函数都是非函数函数(如果我错过了一个标准的命令,请纠正我)除了交换,析构函数和原始操作的列表之外.对于未在库中完全定义的函数来说,要求用户实现nothrows函数似乎相当罕见.
因此,或许要找到问题的根源,你应该主要假设任何东西都可以抛出C++,当你发现绝对不能抛出异常的东西时,可以把它作为一种简化.编写异常安全代码就像编写无错代码一样 - 它比听起来更难,老实说通常不值得努力.此外,异常不安全代码和强大的非运行函数之间存在许多级别.看到这个关于编写异常安全代码作为这些要点的验证的很棒的答案:你(真的)编写异常安全代码吗?.有关异常安全的更多信息,请访问http://www.boost.org/community/exception_safety.html.
对于代码开发,我听过教授和编码专家关于应该和不应该抛出异常以及这些代码应该提供什么保证的不同意见.但是一个相当一致的断言是,很容易抛出异常的代码应该非常清楚地记录下来,或者在函数定义中指出抛出的能力(并不总是仅适用于C++).可能抛出异常的函数比不抛出的函数更常见,并且知道可能发生的异常非常重要.但是保证将一个输入除以另一个输入的函数永远不会抛出0分频异常可能是非常不必要/不需要的.因此,对于安全的代码执行,nothrow可以让人放心,但不是必需的或者总是有用的.
回应对原始问题的评论:
人们有时会说当抛出容器或一般情况下抛出构造函数是异常的,并且应始终使用两步初始化和is_valid检查.但是,如果构造函数失败,它通常是不可修复的或处于唯一错误的状态,否则构造函数将首先解决问题.检查对象是否有效就像在初始化代码周围放置try catch块一样困难,因为对象你知道有很多机会抛出异常.哪个是正确的?通常以代码库的其余部分或您的个人偏好中使用的为准.我更喜欢基于异常的代码,因为它让我感觉更灵活,没有大量的行李代码检查每个对象的有效性(其他人可能不同意).
这会给您留下原始问题以及评论中列出的扩展名?好吧,从提供的资源和我自己的经验来看,担心在C++的"异常安全"视角下不使用函数通常是处理代码开发的错误方法.请记住,您知道可能合理地抛出异常并适当处理这些情况的函数.这通常涉及IO操作,您无法完全控制触发异常的内容.如果你得到一个你从未想过或不想到的异常,那么你的逻辑中有一个错误(或者你对函数使用的假设),你需要修改源代码以适应.试图保证代码是非平凡的(有时甚至是那时)就像说服务器永远不会崩溃 - 它可能非常稳定,但你可能不会100%肯定.
小智 5
如果您想对此问题进行详尽详细的回答,请访问http://exceptionsafecode.com/,并观看仅涵盖C ++ 03的85分钟视频或涵盖两个主题的三小时(分为两部分)视频C ++ 03和C ++ 11。
编写异常安全代码时,除非我们知道不同,否则我们假定所有函数都抛出。
简而言之,
*)基本类型(包括的数组和指向的指针)可以与不涉及用户定义的运算符(例如,仅使用基本整数和浮点值的运算符)进行分配以及与之一起使用。请注意,除以零(或除以数学方式未定义其结果的任何表达式)是未定义的行为,取决于实现方式,它可能会抛出也可能不会抛出。
*)析构函数:发出异常的析构函数在概念上没有错,标准也不禁止它们。但是,良好的编码准则通常会禁止使用它们,因为该语言不能很好地支持这种情况。(例如,如果STL容器中的对象的析构函数抛出,则行为未定义。)
*)使用swap()是提供强大的异常保证的一项重要技术,但前提是swap()是非抛出的。通常,我们不能假定swap()是非抛出的,但是视频介绍了如何在C ++ 03和C ++ 11中为用户定义类型创建非抛出的交换。
*)C ++ 11引入了移动语义和移动操作。在C ++ 11中,swap()是使用move语义实现的,并且move操作的情况类似于swap()的情况。我们不能假定移动操作不会抛出,但是通常我们可以为我们创建的用户定义类型创建非抛出移动操作(并且为标准库类型提供了这些操作)。如果我们在C ++ 11中提供非抛出移动操作,则可以免费获得非抛出swap(),但是出于性能目的,我们可以选择以任何方式实现自己的swap()。同样,这是视频中的详细介绍。
*)C ++ 11引入了noexcept运算符和函数修饰符。(现在不推荐使用Classic C ++的“ throw()”规范。)它还提供了功能自省功能,以便可以根据是否存在非抛出操作来编写代码以不同方式处理情况。
除了视频外,exceptionsafecode.com网站上还有关于例外的书籍和文章的参考书目,需要针对C ++ 11进行更新。
| 归档时间: |
|
| 查看次数: |
1253 次 |
| 最近记录: |