2013-04-18 116 views
0

有几个特殊功能,通常保证不丢excpetions,如:无抛出异常保证和堆栈溢出

  • 析构函数
  • swap方法

考虑以下swap实施,如this answer中所述:

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就好,没有例外会在这里引发。为什么?

+0

析构函数不保证不抛出异常。 –

+0

好的,他们通常应该这样做,尽管他们并不强迫它。 – Mikhail

+1

@KerrekSB:我的事,所以我不知道,如果他们不;-p –

回答

4

一般来说,你不能处理用完堆栈。标准没有说明如果你用完堆栈会发生什么,也不会谈论堆栈是什么,有多少可用等。操作系统可以让你在构建可执行文件或运行时,如果你正在编写库代码,所有这些都是毫不相关的,因为你无法控制进程有多少堆栈,或者在用户调用库之前已经使用了多少堆栈。

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

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

2

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

然后你的程序处于不可恢复的故障状态,并且没有实际的方法来处理这种情况。希望溢出已经导致了分段错误并终止了程序。

但是现在我们不能保证不抛

我从来没有遇到过,将抛出一个异常,在该状态的实现,我是相当害怕,如果它没有。

但是所有的权威来源只是使用swap就好,没有例外会在这里抛出。为什么?

我读过的权威信息来源(比如this one)并不是“只用它就好”;他们说如果你有你有(例如)一个非投掷swap函数,而一个非投掷析构函数然后你可以使用它们的函数提供异常安全保证。

它根据自己的异常担保进行分类的功能是非常有用的:

  • 基础:异常放下一切在一个有效的,但不确定状态
  • 强:异常离开状态不变
  • 无抛出:无异常将被抛出。

比普通方法来提供“强”的保证是:

  • 这样做可能对国家的临时副本
  • 交换与现场状态下复制丢工作(需要非投掷交换操作)
  • 打碎旧的国家(需要非投掷析构函数)

如果您还没有一个无掷瓜拉尼从这些行动开始,那么提供强有力的保证更加困难,也许不可能。

+0

但是,如果我拥有一个不抛出的'swap',但是当我真的试图调用它时,我用完了堆栈?我是否应该阅读“不投掷”,如“不投掷,如果叫”? – Mikhail

+2

@Mikhail:如果你用完了,那么所有的投注都关闭。正如我在第一段中所说的那样,这是一种不可恢复的情况,希望该计划能够立即终止。在该状态下抛出异常将是疯狂的,希望没有实现尝试。所以你应该把“不投掷”看作“永不投掷”。 –