![](/img/trans.png)
[英]Does the C++ standard guarantee that uniform initialization is exception-safe?
[英]Does the current standard guarantee to invoke the destructor for subobject when the initialization of the complete object throws an exception
在except.ctor部分,規則規定:
- 當控制從拋出異常的點傳遞到處理程序時,具有自動存儲持續時間的對象被本子條款中指定的進程銷毀,稱為堆棧展開。
- [...]
- 如果除委托構造函數之外的 object 的初始化或銷毀因異常而終止,則為對象的每個直接子對象調用析構函數,並且對於完整的 object,虛擬基礎 ZA2F2ED4F8EBC2CBB4C21A20 初始化已完成init]) 並且其析構函數尚未開始執行,除了在銷毀的情況下,不會銷毀類似聯合的 class 的變體成員。 [ 注意:如果這樣的 object 具有延長臨時 object 的生命周期的引用成員,這將結束引用成員的生命周期,因此臨時 object 的生命周期實際上不會延長。 — 尾注] 子對象按照其構建完成的相反順序被銷毀。 這種破壞在進入構造函數或析構函數的函數嘗試塊的處理程序之前排序,如果有的話。
根據第 3 條,哪些狀態也可以被視為堆棧展開過程的一部分。 由於第一條規則聽起來像堆棧展開的調用僅適用於具有自動存儲持續時間的 object 。 堆棧展開不會調用具有動態存儲持續時間或其他持續時間的 object 嗎?
#include <iostream>
struct A{
~A(){
std::cout<<"invoke\n";
}
};
struct B{
B(){
throw 0;
}
A a;
};
int main(){
try{
auto ptr = new B{};
}catch(int){
}
}
顯然,子對象a
占用了具有動態存儲持續時間的類型B的完整object內的存儲。 在我看來,應該調用 A 的析構函數,因為它已經在 B 的初始化中完全構造。 它是這些編譯器的擴展嗎? 如何解讀它?
通過 [except.ctor]/3 的簡單措辭,它適用於具有任何存儲期限的對象,只要它們是 object 的子對象,其構造因異常而終止。 這不應該有爭議。
但是,[except.ctor] 的措辭隨着時間的推移發生了變化,這似乎造成了 OP 注意到的一些問題。 背景是以前的寫法和現在的寫法類似,“stack unwinding”只指銷毀自動對象,有人注意到這造成了不一致,當沒有找到匹配的處理程序時,它不是保證是否發生堆棧展開,但保證發生子對象銷毀(因為文本中沒有說如果找不到處理程序可能不會發生)。 這是CWG 1774 。 CWG 同意這種不一致是不可取的(也許是無意的,盡管該頁面沒有說明)。 因此,措辭被更改,以便子對象銷毀將成為“堆棧展開”的一個方面,因此涵蓋在 [except.handle]/9 下,而不是作為一個單獨的過程。 但后來,為了解決與異常無關的不同 DR ,又添加了舊的措辭,我 90% 確定這是無意的。 CWG2256 決議的目的只是為了避免歧視可破壞的對象,而不是真正改變異常處理的任何內容。
因此,當前的措辭是有缺陷的,並且該標准仍應被理解為好像“堆棧展開”包括子對象破壞(即CWG 1774 的決議)。 您甚至可以通過編輯方式修復此問題(即,針對標准源提交拉取請求)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.