2016-03-08 111 views
4

據我所知,unique_ptr是某個對象的單一所有者,當它超出範圍時,它會釋放該對象。我不明白的是以下情況:重定向unique_ptr時會發生什麼?

unique_ptr<int> p(new int(1)); 
p = unique_ptr<int>(new int(2)); 

new int(1)如果p被重定向到另一個存儲位置new int(2)(因爲p只能擁有其中的一個)與第一對象會發生什麼?

+1

它消失了,永遠消失了,但保證能夠正確清理。如果類型不是POD,它的析構函數將被調用(除非使用了一些自定義釋放器)。 – Tas

+0

這就是我不明白的地方。誰會把他清理乾淨,因爲他不是沒有人擁有的? – Tracer

+0

'unique_ptr'是一個像其他任何對象一樣的構造函數和析構函數。當調用'p = unique_ptr'時,將調用'p'的析構函數來清理內存。 – Tas

回答

7

unique_ptr破壞它擁有當unique_ptr是銷燬對象編號或重新編號爲。例如:

#include <iostream> 
#include <memory> 
using namespace std; 

struct T { 
    T(int x) : x(x) { 
     cout << "T(" << x << ")\n"; 
    } 
    ~T() { 
     cout << "~T(" << x << ")\n"; 
    } 
    int x; 
}; 

int main() { 
    unique_ptr<T> p(new T(1)); 
    p = unique_ptr<T>(new T(2)); 
} 

這將打印:

  • T(1)創建所述第一對象時。
  • T(2)當第二個對象被創建時。
  • ~T(1)當第一個對象被賦值運算符p釋放時。
  • ~T(2)當第二個對象被p的析構函數釋放時。
+0

如果'T(1)'被'p'的賦值操作符銷燬,在這種情況下會發生什麼? 'unique_ptr p(new T(1)); unique_ptr p2(new T(2)); p2 = move(p);'誰毀掉了'新T(2)'? – Tracer

+0

@Tracer:'p2'在分配給它時做了。 – GManNickG

+0

@Tracer:'p2'的移動賦值運算符必須在將'new T(1)'從'p'移動到'p2'之前銷燬'new T(2)'。 –

1

unique_ptr被定義爲確保第一個int被正確解除分配,因此它會調用delete,釋放保留的內存。

這是這段代碼有點相同:

int* p = new int(1); 
delete p; 
p = new int(2); 

會發生什麼事了詳細是這樣的:

  • 您創建一個使用new int(1)一個新的整數。
  • 您將指向此新int的指針傳遞給名爲p的剛創建的實例unique_ptr。這是一個剛剛存儲指針的對象。
  • 您使用new int(2)創建第二個int。
  • 您可以使用unique_ptr<int>(new int(2))將此指針傳遞給新的unique_ptr,這是unique_ptr的臨時實例(我們將在第二秒看到原因)並將指針存儲到第二個int中。
  • 您將臨時對象分配給p。現在賦值運算符被定義爲刪除先前擁有的對象(第一個int)並獲取被賦值的unique_ptr(第二個int)擁有的對象的所有權。一個實現如下所示。此時p擁有第二個int,第一個int被刪除,臨時不擁有對象(持有nullptr)。
  • 由於最後一部分臨時unique_ptr超出了範圍,因爲我們從未給它命名或存儲對它的引用,所以它的析構函數被調用。但它只能保持nullptr

因此,使用原始指針更詳細相當於將是這樣的:

int* p = new int(1); //create an int 
{ 
    int* tmp = new int(2); //create second int 
    int* del = p; //we need to delete this (first int) 

    //take ownership of the temporary (second int) 
    p = tmp; 
    tmp=nullptr; 

    //delete the old object (first int) 
    delete del; 
} //tmp and del go out of scope here, but tmp holds the nullptr and del is deleted 
//first int is deleted, p points to the second int here 

編輯示蹤劑: 這是由Visual Studio所使用的實現(註釋是<memory>一部分井):

typedef unique_ptr<_Ty> _Myt; 

_Myt& operator=(_Myt&& _Right) _NOEXCEPT 
{ // assign by moving _Right 
    if (this != &_Right) 
    { // different, do the move 
     reset(_Right.release()); 
     this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter()); 
    } 
return (*this); 
} 

void reset(pointer _Ptr = pointer()) _NOEXCEPT 
{ // establish new pointer 
    pointer _Old = get(); 
    this->_Myptr() = _Ptr; 
    if (_Old != pointer()) 
     this->get_deleter()(_Old); 
} 
+0

切換指針?你確定嗎? C++標準中是否有支持該語句的內容? – Tracer

+0

@Tracer:我把它與shared_ptr混合在一起。在Visual Studio附帶的shared_ptr的實現中,臨時shared_ptr在賦值運算符中被複制構建。然後當前指針與臨時切換。當臨時超出範圍時,shared_ptr本身保存分配的值,臨時存儲舊值,減少其引用計數/破壞對象。但由於這個問題是關於unique_ptr,我相應地更新了答案。 – Anedar