0

有几个特殊功能通常可以保证不抛出异常,例如:

  • 析构函数
  • swap方法

考虑以下swap实现,如本答案所述:

friend void swap(dumb_array& first, dumb_array& second)
{
    using std::swap; 

    swap(first.mSize, second.mSize);  
    swap(first.mArray, second.mArray);  // What if stack overlow occurs here?
}

它使用两个swap函数——整数和指针。如果第二个函数会导致堆栈溢出怎么办?对象将损坏。我猜这不是std::exception,它是某种系统异常,例如Win32-exception. 但是现在我们不能保证不抛出,因为我们正在调用一个函数。

但是所有权威来源都可以正常使用swap,这里永远不会抛出异常。为什么?

4

2 回答 2

4

通常,您无法处理堆栈不足的情况。该标准没有说明如果您用完堆栈会发生什么,也没有说明堆栈是什么,可用的数量等。操作系统可能会让您在构建可执行文件时或运行时控制它,如果您正在编写库代码,所有这些都相当无关紧要,因为您无法控制进程有多少堆栈,或者在用户调用您的库之前已经使用了多少。

您可以假设堆栈溢出导致操作系统在您的程序之外执行某些操作。一个非常简单的操作系统可能会让它变得怪异(未定义的行为),一个严重的操作系统可能会破坏进程,或者如果你真的很不幸,它会抛出一些实现定义的异常。我实际上不知道 Windows 是否为堆栈溢出提供了 SEH 异常,但如果提供了,那么最好不要启用它。

如果您担心,可以将您的swap功能标记为noexcept. 然后在符合要求的实现中,任何试图离开函数的异常都会导致程序terminate(). 也就是说,它noexcept以拿出你的程序为代价来履行合同。

于 2013-04-18T10:35:09.450 回答
2

如果第二个函数会导致堆栈溢出怎么办?

那么你的程序就处于不可恢复的故障状态,没有切实可行的办法来处理这种情况。希望溢出已经导致分段错误并终止程序。

但现在我们不能保证不扔

我从来没有遇到过会在那种状态下抛出异常的实现,如果真的发生了,我会很害怕。

但是所有权威来源都只是使用交换就可以了,这里永远不会抛出异常。为什么?

我读过的权威资料(例如这个)并不是“随便用就行”;他们说,如果你有(例如)一个非抛出swap函数和一个非抛出析构函数,那么你可以从使用它们的函数中提供异常安全保证。

根据异常保证对函数进行分类很有用:

  • 基本:异常使所有内容都处于有效但未指定的状态
  • 强:异常使状态保持不变
  • No-throw:不会抛出异常。

提供“强”保证的常用方法是:

  • 做可能导致临时状态副本的工作
  • 将该副本与实时状态交换(需要非抛出交换操作)
  • 销毁旧状态(需要一个不抛出的析构函数)

如果您没有从这些操作中获得不投掷保证,那么提供强有力的保证会更加困难,甚至可能是不可能的。

于 2013-04-18T10:39:03.397 回答