[英]Moving semantics of unique_ptr
Lets consider the following piece of code: 让我们考虑以下代码:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function: 在另一个功能中:
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.
}
I don't understand why u_ptr
in line X
is still alive. 我不明白为什么
X
行中的u_ptr
仍然存在。 After all I forced him to be moved (std::move). 毕竟,我迫使他感动(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;
}
You didn't show us that code to function f
, but presumably it didn't move the pointer, even though it had permission to. 您没有向我们展示该函数
f
代码,但是即使它具有许可,也可能没有移动指针。
You passed the unique_ptr
by reference. 您通过引用传递了
unique_ptr
。 If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to. 如果函数调用确实移动了它,那么该函数将无法使用它,因为它将在函数有机会消失之前就消失了。
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. 如果希望函数调用实际移动指针,则需要按值传递指针,而不是引用。 That value would be a
unique_ptr
for it to be moved into. 该值将是一个要移入的
unique_ptr
。 In that case, you should declare the function as taking a std::unique_ptr<T>
instead of a std::unique_ptr<T>&&
. 在这种情况下,应声明该函数采用
std::unique_ptr<T>
而不是std::unique_ptr<T>&&
。 Then you can actually invoke the move constructor when you call the function. 然后,您实际上可以在调用函数时调用move构造函数。
Update : With your latest change, the unique_ptr
would no longer reference any valid object due to the move construction. 更新 :由于您的最新更改,由于移动构造,
unique_ptr
将不再引用任何有效对象。 You just never check that it does. 您只是从未检查过它。 Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object.
无论对象是有效的还是销毁的,调用不访问任何成员变量的非虚拟方法都可以相同地工作,因为该对象不需要任何东西。 You also never made the
unique_ptr
actually point to anything. 您也从未使
unique_ptr
实际上指向任何东西。
Instead, make the unique_ptr
point to something. 而是使
unique_ptr
指向某物。 After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. 移动后,尝试调用虚拟函数或访问其值被析构函数更改的成员。 Like this:
像这样:
#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;
}
The reason why your call to show
doesn't crash is because it doesn't use the this
pointer (it doesn't try to modify or access a data member). 您的
show
调用不会崩溃的原因是因为它不使用this
指针(它不会尝试修改或访问数据成员)。
Try this: 尝试这个:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
无效f(std :: unique_ptr && ref)
This is the answer when you initially had your f
function taking a rvalue reference && . 这是您最初让
f
函数采用右值引用&&时的答案。
Your function takes a rvalue reference . 您的函数带有右值引用 。 Therefore, no new
unique_ptr
object is created yet, you are simply passing a reference
. 因此,还没有创建新的
unique_ptr
对象,您只是传递了reference
。
Inside your f
function, if you create aa local unique_ptr
, with the parameter uptr
, then finally uptr
will be moved to create that new object. 在
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));
}
The important thing to always know is that std::move
is simply a static_cast
. 要始终知道的重要事情是
std::move
仅仅是static_cast
。
If you pass a lvalue
to std::move
, it returns a rvalue
. 如果将
lvalue
传递给std::move
,它将返回一个rvalue
。 If you pass a rvalue
, it returns a rvalue
. 如果传递一个
rvalue
,它将返回一个rvalue
。 That's it. 而已。
in the line f(std::unique_ptr<T>&& uptr)
uptr
is not an object - it's a reference. 在
f(std::unique_ptr<T>&& uptr)
uptr
不是对象-它是引用。 a reference which capable to catch temporeries and mutate them. 能够捕获临时变量并对其进行突变的参考。
it's like asking why doesn't the object get cloned in the next example 就像问下一个示例为什么不克隆对象
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_
is passed by "regular" reference and won't get copied - this is what pass by reference means. str_
由“常规”引用传递,不会被复制-这就是引用传递的意思。
std::move
only cast l-value to r-value-reference, which uptr
in f(std::unique_ptr<T>&& uptr)
can reference, it's a reference referencing an object. std::move
仅投-1-值r值参考,其uptr
在f(std::unique_ptr<T>&& uptr)
可以引用,它是引用一个对象的引用。 opposed to the common conception, std::move
won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. 与通常的概念相反,
std::move
本身不会做任何移动,只会将对象强制转换为move构造函数/ assg的r值引用。 operator to kick in. 操作员加入。
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference. 在这里,由于指针没有被移动,因此仍然保留有效数据,仅将其转换为r-value-reference。
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
如果要移动对象,则必须将参数声明为对象,而不是引用:
f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure. 在编辑中,您有不确定的行为,因此一切都会发生。
Your function f
may not in fact move the pointer. 您的函数
f
实际上可能不会移动指针。 Merely taking an object by &&
does not modify the object. 仅通过
&&
取得对象不会修改该对象。
u_ptr->do_sth()
may invoke a static member function or a member function that does not access the object ( this
) and this is why it does not crash. u_ptr->do_sth()
可以调用静态成员函数或不访问对象的成员函数( this
),这就是为什么它不会崩溃的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.