簡體   English   中英

std::shared_ptr:reset() 與賦值

[英]std::shared_ptr: reset() vs. assignment

這是一個基本問題,但我沒有找到以前的帖子。 以下問題的標題聽起來可能與我的問題相同,但問題本身與標題不匹配: 使用 shared_ptr.reset 還是 operator = 更好?

我對std::shared_ptrreset()成員函數的目的感到困惑:除了賦值運算符之外,它還有什么作用?

具體來說,給出定義:

auto p = std::make_shared<int>(1);
  1. 以下兩行是否等效:

     p = std::make_shared<int>(5); p.reset(new int(5));
  2. 這些怎么樣:

     p = nullptr; p.reset();

如果這兩行在兩種情況下都是等價的,那么reset()的目的是什么?


編輯:讓我重新表述這個問題以更好地強調它的觀點。 問題是: reset()可以讓我們實現一些沒有它就不容易實現的東西?

使用reset() ,傳遞給 reset 的參數不需要是托管對象(也不能是); 而 with =右側必須是托管對象。

所以這兩行給你相同的最終結果:

p = std::make_shared<int>(5); // assign to a newly created shared pointer
p.reset(new int(5)); // take control of a newly created pointer

但我們不能這樣做:

p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior

如果沒有reset()您將無法在不創建共享指針並分配它的情況下將共享指針重新分配給不同的原始指針。 如果沒有=您將無法使共享指針指向另一個共享指針。

在某些情況下,可以通過reset來避免動態內存分配。 考慮代碼

std::shared_ptr<int> p{new int{}};  // 1
p.reset(new int{});                 // 2

第 1 行發生了 2 個動態內存分配,一個用於int對象,第二個用於shared_ptr的控制塊,它將跟蹤對托管對象的強/弱引用的數量。

第 2 行再次為新的int對象進行動態內存分配。 reset的主體內, shared_ptr將確定沒有其他對先前管理的int強引用,因此它必須delete它。 由於也沒有任何弱引用,它也可以釋放控制塊,但在這種情況下,實現重用相同的控制塊是謹慎的,因為否則無論如何它都必須分配一個新的。

如果您總是不得不使用賦值,則上述行為是不可能的。

std::shared_ptr<int> p{new int{}};    // 1
p = std::shared_ptr<int>{new int{}};  // 2

在這種情況下,第 2 行對shared_ptr構造函數的第二次調用已經分配了一個控制塊,因此p將不得不釋放自己現有的控制塊。

我不會包括你的第一個子問題背后的基本原理,即通過make_shared或從指針構造之間的差異,因為這種差異在幾個不同的位置突出顯示,包括這個很好的問題

但是,我認為區分使用resetoperator=是有建設性的。 前者放棄由shared_ptr管理的資源的所有權,如果shared_ptr碰巧是唯一所有者,則通過銷毀它,或者通過遞減引用計數。 后者意味着與另一個shared_ptr共享所有權(除非您正在移動構建)。

正如我在評論中提到的,重要的是傳入reset的指針不屬於另一個共享或唯一指針,因為這會在兩個獨立管理器銷毀時產生未定義的行為 - 他們都會嘗試delete資源。

reset一個用例可能是共享資源的延遲初始化。 您只希望shared_ptr管理一些資源,例如內存,如果您真的需要它。 進行直接分配,例如:

std::shared_ptr<resource> shared_resource(new resource(/*construct a resource*/));

如果從未真正需要它,則可能會浪費。 要使用延遲初始化來做到這一點,可能適用於以下內容:

std::shared_ptr<resource> shared_resource;
void use_resource()
{
       if(!shared_resource)
       {
            shared_resource.reset(new resource(...));
       }

       shared_resource->do_foo();
}

在這種情況下使用resetswap或分配給臨時shared_ptr更簡潔。

reset()更改現有shared_ptr的托管對象。

p = std::shared_ptr(new int(5)); 和 p.reset(new int(5));

前者涉及創建一個新的shared_ptr並將其移動到一個變量中。 后者不會創建新對象,它只是更改由shared_ptr管理的底層指針。

換句話說,這兩者旨在用於不同的情況。 分配用於當您有一個shared_ptr並在您有一個原始指針時reset

要記住的另一件事是,在移動分配存在並嚴重影響最新版本之前, shared_ptr在 boost 中可用。 無需移動分配就能夠在不復制的情況下更改shared_ptr是有益的,因為它可以為您節省額外對象的簿記。

暫無
暫無

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

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