提供正确的移动语义 [英] Providing correct move semantics
问题描述
我目前正试图弄清楚如何使用包含指向分配的内存的指针的对象正确地执行移动语义。我有一个大的数据结构,其中包含一个内部原始指针到实际存储(出于效率的原因)。现在我添加了一个移动构造函数并移动 operator =()
。在这些方法中,我 std :: move()
指向新结构的指针。但我不知道如何处理其他结构的指针。
I am currently trying to figure out how to do move semantics correctly with an object which contains a pointer to allocated memory. I have a big datastructure, which contains an internal raw pointer to the actual storage (for efficiency reasons). Now I added a move constructor and move operator=()
. In these methods I am std::move()
ing the pointer to the new structure. However I am not sure what to do with the pointer from the other structure.
这里是一个简单的例子:
Here is a simple example of what I am doing:
class big_and_complicated {
// lots of complicated code
};
class structure {
public:
structure() :
m_data( new big_and_complicated() )
{}
structure( structure && rhs ) :
m_data( std::move( rhs.m_data ) )
{
// Maybe do something to rhs here?
}
~structure()
{
delete m_data;
}
private:
big_and_complicated * m_data;
}
int main() {
structure s1;
structure s2( std::move( s1 ) );
return 0;
}
现在从我所理解的 std: :move(s1)到
s2
唯一可以安全地在 s1
ist来调用它的构造函数。然而,就我所见,这将导致删除 s1
在析构函数中的指针,渲染 s2
无用的。所以我猜想,当 std :: move()
指针时,我必须做一些事情来渲染析构函数。就我可以看到在这里最安全的事情是在移动的对象中将其设置为 0
,因为这将转变 delete
转换为无操作。这个推理到目前为止是正确的吗?或者是 std :: move()
实际上足够聪明,为我null的指针,使其使用安全吗?到目前为止,我没有看到在实际的测试套件崩溃,但我没有确保移动构造函数实际上被调用。
Now from what I understand, after the std::move( s1 )
to s2
the only thing that is safe to do on s1
ist to call its constructor. However as far as I can see, this would lead to deleting the pointer contained within s1
in the destructor, rendering s2
useless as well. So I am guessing I have to do something to render the destructor safe when std::move()
ing the pointer. As far as I can see the safest thing to do here, is to set it to 0
in the moved object, since this would turn the delete
into a no-op later on. Is this reasoning correct so far? Or is std::move()
actually smart enough to null out the pointer for me, rendering its usage safe? So far I am seeing no crashes in the actual test-suite, but I have not made sure the move-constructor is actually called.
推荐答案
移动指针与复制指针没有区别,并且不会将移动的值设置为null(moving在这里引用,因为 std :: move
不会移动任何东西,它只是更改参数的值类别)。只需复制 rhs
'指针,然后将其设置为 nullptr
:
"Moving" a pointer is no different than copying one and does not set the moved-from value to null ('moving' is in quotes here because std::move
does not move anything really, it just changes the value category of the argument). Just copy rhs
' pointer then set it to nullptr
:
struct structure
{
structure()
: m_data{new big_and_complicated{}}
{ }
structure(structure&& rhs)
: m_data{rhs.m_data}
{
rhs.m_data = nullptr;
}
structure& operator =(structure&& rhs)
{
if (this != &rhs)
{
delete m_data;
m_data = rhs.m_data;
rhs.m_data = nullptr;
}
return *this;
}
~structure()
{
delete m_data;
}
private:
big_and_complicated* m_data;
structure(structure const&) = delete; // for exposition only
structure& operator =(structure const&) = delete; // for exposition only
}
更好的是使用 std :: unique_ptr< big_and_complicated>
而不是 big_and_complicated *
,您不需要自己定义任何内容:
Better yet, use std::unique_ptr<big_and_complicated>
instead of big_and_complicated*
and you don't need to define any of this yourself:
#include <memory>
struct structure
{
structure()
: m_data{new big_and_complicated{}}
{ }
private:
std::unique_ptr<big_and_complicated> m_data;
}
最后,除非你真的想要结构
保持不可复制,你最好只是在 big_and_complicated
里面实现适当的移动语义,并拥有结构
直接持有 big_and_complicated
对象。
Lastly, unless you actually want structure
to remain non-copyable, you're better off just implementing proper move semantics inside of big_and_complicated
and having structure
hold a big_and_complicated
object directly.
这篇关于提供正确的移动语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!