簡體   English   中英

為什么 std::vector 允許對其包含的類型使用可拋出的移動構造函數?

[英]Why does std::vector allow the use of a throwable move constructor for the type it contains?

顯然, std::move_if_noexcept()將調用移動構造函數,即使它沒有被標記為noexcept如果沒有可用的復制構造函數。

來自cpprefeerence.com (重點是我的):

筆記

例如,這被std::vector::resize ,它可能必須分配新存儲,然后將元素從舊存儲移動或復制到新存儲。 如果在此操作期間發生異常,則std::vector::resize撤消它到目前為止所做的一切,這僅在使用std::move_if_noexcept來決定是使用移動構造還是復制構造時才有可能。 (除非復制構造函數不可用,在這種情況下,無論哪種方式都使用移動構造函數並且可以放棄強異常保證)

由於std::vector在重新分配時使用此函數,這可能會使向量和應用程序處於不確定狀態。 那么,為什么會允許這樣做呢?

假設您正在做vector在使用move_if_noexcept時正在做的事情。 也就是說,您有一些對象obj ,您需要從obj構造該類型的新值。 之后,您將刪除obj 這是移動對象的主要情況,因此vector在可能的情況下會這樣做。

如果移動是noexcept ,那么移動obj根據定義是異常安全的。 如果它不是noexcept ,那么你需要問:如果移動構造函數拋出會發生什么? 在這種情況下obj的狀態是什么? 答案是……你不知道。 更糟糕的是,您已經成功移動的任何對象的狀態如何? 你能把它們搬回去嗎?

但是,當談到復制構造函數時,您確實知道. 復制構造函數接受一個const&到源對象。 所以根據定義,失敗的復制操作不能修改obj (是的,我們知道你可以const_cast ,但這使你的復制構造函數成為謊言。像這樣的謊言就是auto_ptr不再存在的原因,我猜有一個毯子標准中禁止說謊的復制構造函數)。 因此,在失敗的副本上, obj處於其原始狀態。

因此,如果移動可以拋出,則首選復制,因為這提供了強大的異常保證:如果發生異常,一切都會恢復原狀。

但是,如果您唯一的選擇是投擲移動,那么您有兩個選擇:使這種類型永遠不能與vector一起使用,或者提供該類型本身在移動失敗時提供的任何異常保證。 后者是被選擇的。

這是允許的,因為那是您要求的 您選擇的類型不允許強異常保證,因此無法提供。 但是您仍然可以制作此類類型的vector 您只需要處理不可復制的運動失敗的可能性。

既然你是那種使用不能提供強異常保證的類型的人,你顯然必須知道如何處理這些場景,對吧?

暫無
暫無

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

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