[英]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值參考,其uptr
在f(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.