2013-04-18 76 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:如果你用完了,那麼所有的投注都關閉。正如我在第一段中所說的那樣,這是一種不可恢復的情況,希望該計劃能夠立即終止。在該狀態下拋出異常將是瘋狂的,希望沒有實現嘗試。所以你應該把「不投擲」看作「永不投擲」。 –