簡體   English   中英

為什么list <unique_ptr>中的unique_ptr的std :: move()沒有真正移動它?

[英]Why doesn't std::move() of unique_ptr from list<unique_ptr> really move it?

using Ptr = std::unique_ptr<int>;

Ptr f(bool arg) {
  std::list<Ptr> list;
  Ptr ptr(new int(1));
  list.push_back(std::move(ptr));

  if (arg) {
    Ptr&& obj1 = std::move(list.front());
    // Here |obj1| and |list.front()| still point to the same location!
    list.pop_front();
    return std::move(obj1);
  }
  else {
    Ptr obj2 = std::move(list.front());
    list.pop_front();
    return obj2;
  }
};

Ptr&& ptr1 = f(true);   // |ptr1| is empty.
Ptr&& ptr2 = f(false);  // |ptr2| is fine.

完整的來源是在這里

我不明白 - 為什么在調用std::move()之后obj1list.front()仍然指向同一個位置?

您有一個 std::unique_ptr內部list引用

Ptr&& obj1 = std::move(list.front());
// ^^ THIS

所以當你這樣做的時候

list.pop_front();

list的唯一指針被銷毀,並且您將留下一些已經被銷毀的對象的懸空引用,這是通過從函數返回而非法使用的。

更新: std::move實際上並沒有移動std::unique_ptr 如果我們看到如何定義std::move ,我們會看到它只返回正在移動的表達式的r值引用。 當你測試它時會變得很有趣:

Ptr&& obj1 = std::move(list.front());
assert(obj1.get() == list.front().get());

你的else子句看起來確實很好,你應該在代碼的其余部分使用該模式。

Ptr obj2 = std::move(list.front());
list.pop_front();  // OK; destroys the moved-from unique_ptr
return obj2;       // OK; obj2 points to something valid and is not a dangling reference

@nosid總結了我想要的答案

沒有move-semantics, std::unique_ptr就不那么有用了。 使用移動語義, 它允許將所有權轉移到另一個對象

使用list.push_back(std::move(ptr)); 您將數據的所有權轉移到新元素並將ptr保留為nullptr狀態( 在此處閱讀 )。

之后,如果arg為true,則由於list.front() 返回對容器中第一個元素的引用 ,因此std::move從中獲取r值並將其提供給r值引用obj1。 請注意,您沒有將所有權轉移到另一個對象,因為您只要求對數據進行r值引用。 最后,r值引用是對值的引用

在上面的特定情況中,關於cout語句,它等同於僅獲得對象的簡單引用

Ptr& obj1 = list.front();

現在你將元素放入列表中,obj1 r值引用“指向”相同的數據,修改一個將導致修改

Ptr&& obj1 = std::move(list.front());
std::cout << obj1.get() << std::endl << list.front().get() << std::endl; // same address
obj1.reset(new int(2));
std::cout << obj1.get() << std::endl << list.front().get() << std::endl; // same other address

如果你是假的,就像在虛假的情況下一樣

Ptr obj1 = std::move(list.front());

然后你將擁有所有權(因此列表對象的nullptr-ify)轉移到obj1。

如果你按照上面的推理,你也可以實現這一點

list.pop_front();

銷毀unique_ptr對象並將r值引用保留為未定義狀態。 你不應該真正歸還它(並使用它)。

暫無
暫無

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

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