![](/img/trans.png)
[英]Why does exporting a type alias such as std::vector<std::string> in a module allow use of both std::vector and std::string in some internal partition?
[英]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.