簡體   English   中英

C ++ STL堆棧問題:如果堆棧為空,為什么pop()不會拋出異常?

[英]C++ STL stack question: Why does pop() not throw an exception if the stack is empty?

為什么std :: stack :: pop()如果堆棧為空並且沒有任何內容可以拋出異常?

(我正在為自己的代碼設計一個專用的堆棧,並想知道這種方法的權衡(需要人們手動檢查堆棧是否為空)而不是拋出異常。

我的猜測是,雖然C ++支持異常處理,但它帶來了很小的運行時開銷,因此,為了獲得最大性能,決定不在std :: stack :: pop中拋出異常。

我認為pop()不必拋出異常的原因與效率或性能無關 ,而是與 - 例外。

正如其他地方所說:

  1. SGI解釋: http//www.sgi.com/tech/stl/stack.html人們可能想知道為什么pop()返回void而不是value_type。 也就是說,為什么必須使用top()和pop()來檢查和刪除頂部元素,而不是將兩者組合在一個成員函數中? 事實上,這種設計有充分的理由。 如果pop()返回頂部元素,則必須按值而不是按引用返回:按引用返回將創建一個懸空指針。 然而,按值返回是低效的:它涉及至少一個冗余復制構造函數調用。 由於pop()不可能以高效和正確的方式返回值,因此更不明智地返回任何值並要求客戶端使用top()來檢查值堆棧的頂部。

  2. std :: stack <T>是一個模板。 如果pop()返回頂部元素,則必須按值返回,而不是按照上述說明返回。 這意味着,在調用者端,它必須被復制到另一種T類型的對象中。 這涉及復制構造函數或復制賦值操作符調用。 如果這種類型T足夠復雜並且在復制構造或復制分配期間拋出異常怎么辦? 在這種情況下,rvalue,即堆棧頂部(由值返回)簡單地丟失,並且沒有其他方法可以從堆棧中檢索它,因為堆棧的彈出操作已成功完成!

一旦我們得出結論,流行應該回到它彈出,因此它的接口是固定的元素void pop() ,它-這是我的觀點-沒有任何意義了規定時彈出()被調用上發生了什么空堆棧。

請注意,標准要求使用!empty()作為調用pop()的前提條件。

UncleBens(在評論中)肯定有一點,即不在運行時檢查前置條件(C ++ std AFAIK從未規定)具有一定的性能氣味。 但是,引用原始問題的一部分:(強調我的)

(我正在為自己的代碼設計一個專用的堆棧,並想知道這種方法的權衡(需要人們手動檢查堆棧是否為空 )而不是拋出異常。

我會爭辯說, pop()不返回任何東西的事實使得這個問題沒有實際意義。 它(恕我直言)根本沒有意義強制pop()驗證堆棧是否為空,當我們真的沒有從它得到任何回報時(即如果堆棧是空的pop()可以簡單地是一個noop ,(誠然)也沒有由Std規定)。

我想可以問為什么top()不會拋出異常, 或者可以問為什么pop()不返回top元素。 如果pop沒有返回任何內容,拋出一個異常沒有意義(在C ++世界中) - 聲稱它不會拋出異常“因為異常的運行時成本”,就像其他答案似乎暗示的那樣 -恕我直言 - 錯過了重點。

你是對的。 C ++標准始終優先考慮性能和安全性。 但是可能存在包括調試范圍檢查的STL實現。

與C ++中的幾乎所有功能一樣,它們是圍繞您不為不使用的內容付費的概念而設計的。 並非所有環境都支持異常,傳統上,尤其是游戲開發。

因此,如果使用std :: stack,強制使用異常將失敗其中一個設計指南。 即使禁用了異常,您也希望能夠使用堆棧。

我認為值得一提的是,如果堆棧為空,則允許 pop()拋出 - 這不是必需的。 在你的堆棧中,你可以assert堆棧不是空的,那就完全沒問題了(在空堆棧上pop似乎給了UB,所以你可以做任何你想要的,真的)。

除了性能之外,我不認為從空堆棧中彈出是一種特殊情況 - 因此我也不會拋棄它。

例外是可選的,STL希望隨處可用。 認為嵌入式系統:許多C ++代碼,運行時沒有異常支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM