簡體   English   中英

unique_ptr的移動語義

[英]Moving semantics of unique_ptr

讓我們考慮以下代碼:

template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }

在另一個功能中:

void g()
{
    std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
    f(std::move(u_ptr));
X:  u_ptr->do_sth(); // it works, I don't understand why. Details below.
}

我不明白為什么X行中的u_ptr仍然存在。 畢竟,我迫使他感動(std :: move)。

---EDIT---
Ok, so now:
The code is still working:

class T{
    public:
    T(){}

    void show(){
        std::cout << "HEJ!\n";
    }
};

void f(std::unique_ptr<T> ref){
   ref->show();   
}

int main()
{
    std::unique_ptr<T> my;
    my->show();
    f(std::move(my));
    my->show(); // How is it possible. Now, f takes unique_ptr by value 


    return 0;
}

您沒有向我們展示該函數f代碼,但是即使它具有許可,也可能沒有移動指針。

您通過引用傳遞了unique_ptr 如果函數調用確實移動了它,那么該函數將無法使用它,因為它將在函數有機會消失之前就消失了。

如果希望函數調用實際移動指針,則需要按值傳遞指針,而不是引用。 該值將是一個要移入的unique_ptr 在這種情況下,應聲明該函數采用std::unique_ptr<T>而不是std::unique_ptr<T>&& 然后,您實際上可以在調用函數時調用move構造函數。

更新 :由於您的最新更改,由於移動構造, unique_ptr將不再引用任何有效對象。 您只是從未檢查過它。 無論對象是有效的還是銷毀的,調用不訪問任何成員變量的非虛擬方法都可以相同地工作,因為該對象不需要任何東西。 您也從未使unique_ptr實際上指向任何東西。

而是使unique_ptr指向某物。 移動后,嘗試調用虛擬函數或訪問其值被析構函數更改的成員。 像這樣:

#include <iostream>
#include <memory>

class T{
    public:
    T() : valid (true) {}
    ~T() { valid = false; }

    bool valid;

    void show(){
        std::cout << "HEJ! " << valid << std::endl;
    }
};

void f(std::unique_ptr<T> ref){
   ref->show();   
}

int main()
{
    std::unique_ptr<T> my (new T); // Make it point to a new object
    my->show();
    f(std::move(my));
    my->show(); // Try to access


    return 0;
}

您的show調用不會崩潰的原因是因為它不使用this指針(它不會嘗試修改或訪問數據成員)。

嘗試這個:

class T{
    public:
    int v;
    T(){}

    void show(){
        v = 0;
        std::cout << "HEJ!\n";
    }
};

無效f(std :: unique_ptr && ref)

這是您最初讓f函數采用右值引用&&時的答案。

您的函數帶有右值引用 因此,還沒有創建新的unique_ptr對象,您只是傳遞了reference

f函數內部,如果使用參數uptr創建一個本地unique_ptr ,則最終將移動uptr來創建該新對象。

template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
     //move uptr into local_unique_ptr 
     //note that we have to use move again
     //because uptr has a name, therefore its a lvalue.
     auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}

要始終知道的重要事情是std::move僅僅是static_cast

如果將lvalue傳遞給std::move ,它將返回一個rvalue 如果傳遞一個rvalue ,它將返回一個rvalue 而已。

f(std::unique_ptr<T>&& uptr) uptr不是對象-它是引用。 能夠捕獲臨時變量並對其進行突變的參考。

就像問下一個示例為什么不克隆對象

void func(std::string& str);
std::string str_ = "yyy";
func(str_);

str_由“常規”引用傳遞,不會被復制-這就是引用傳遞的意思。

std::move僅投-1-值r值參考,其uptrf(std::unique_ptr<T>&& uptr)可以引用,它是引用一個對象的引用。 與通常的概念相反, std::move本身不會做任何移動,只會將對象強制轉換為move構造函數/ assg的r值引用。 操作員加入。

在這里,由於指針沒有被移動,因此仍然保留有效數據,僅將其轉換為r-value-reference。

如果要移動對象,則必須將參數聲明為對象,而不是引用: f(std::unique_ptr<T> uptr)

在編輯中,您有不確定的行為,因此一切都會發生。

您的函數f實際上可能不會移動指針。 僅通過&&取得對象不會修改該對象。

u_ptr->do_sth()可以調用靜態成員函數或不訪問對象的成員函數( this ),這就是為什么它不會崩潰的原因。

暫無
暫無

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

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