簡體   English   中英

返回shared_ptr和異常安全

[英]Returning shared_ptr and exception safety

我正在閱讀“C ++ Concurrency in action”一書,並嘗試理解線程安全數據結構(例如堆棧)中的異常安全性。 作者說,為了避免競爭條件, pop應該同時執行這兩個操作 - 彈出和返回堆棧中的項目,但是:

如果pop()函數被定義為返回彈出的值,並將其從堆棧中刪除,則可能存在一個問題:彈出的值只有在修改了堆棧后才返回給調用者,但是復制數據以返回調用者可能會引發異常。

這是建議的解決方案:

std::shared_ptr<T> pop()
{
    std::lock_guard<std::mutex> lock(m);
    if(data.empty()) throw runtime_error("empty");
    std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
    data.pop();
    return res;
}

在這種情況下,我們在make_shared行上調用了復制構造函數 如果復制構造函數拋出異常,則堆棧尚未修改,我們很好。

但是,我不知道它與這個片段的區別很大:

T pop2() {
    std::lock_guard<std::mutex> lock(m);
    if(data.empty()) throw runtime_error("empty");
    auto res = data.top();
    data.pop();
    return res;
}

這里我們在data.top()復制構造函數調用,並在返回時移動構造函數 同樣,如果復制構造函數拋出異常,我們就很好,因為堆棧尚未修改。 移動contstructor不應該拋出異常。

我錯過了什么嗎? shared_ptr比較返回到返回(可移動) T什么好處?

如果T不可移動,您的代碼可能最終會執行多個復制構造。 在這種情況下,使用shared_ptr在堆上分配副本可能更有效。

即使T是可移動的,您的代碼仍可能執行多個( 可能代價高昂的)移動構造。 與移動或復制構造任何可能的類型T相比,已知移動構造和/或復制構造shared_ptr相對便宜。

當然,您的里程可能會有所不同,具體取決於具體類型,編譯器以及操作環境和硬件。

move-constructor可能會拋出(一般情況下)。 std::shared_ptr<T>有一個noexcept移動構造函數。

所以在第一種情況下return res; 不能扔,但在第二種情況下return res; 可能會拋出(並且已經調用了data.pop() )。

暫無
暫無

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

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