简体   繁体   English

为什么 std::move 之后的析构函数调用是必要的?

[英]why is the destructor call after the std::move necessary?

In The C++ programming language Edition 4 there is an example of a vector implementation, see relevant code at the end of the message.在 C++ 编程语言第 4 版中,有一个向量实现的示例,请参阅消息末尾的相关代码。

uninitialized_move() initializes new T objects into the new memory area by moving them from the old memory area. uninitialized_move()通过将新的 T 对象从旧的内存区域中移动来将它们初始化到新的内存区域中。 Then it calls the destructor on the original T object, the moved-from object.然后它调用原始 T 对象(即移出对象)的析构函数。 Why is the destructor call necessary in this case?为什么在这种情况下需要调用析构函数?

Here is my incomplete understanding: moving an object means that the ownership of the resources owned by the moved-from object are transferred to the moved-to object.这里是我的不完全理解:移动一个对象,就是将被移动对象所拥有的资源的所有权转移给被移动对象。 The remainings in the moved-from object are some possible members of built-in types that do not need to be destroyed, they will be deallocated when the the vector_base b goes out of scope (inside reserve() , after the swap() call).移动对象中的剩余部分是不需要销毁的内置类型的一些可能成员,当 vector_base b 超出范围时(在reserve()内部,在swap()调用之后),它们将被释放)。 All pointers in the moved-from object are to be put to nullptr or some mechanism is employed to drop ownership of moved-from object on those resources so that we are safe, then why call the destructor on a depleted object when the "vector_base b" destructor will anyway deallocate the memory after the swap is done?移出对象中的所有指针都将被放置到 nullptr 或采用某种机制来删除这些资源上移出对象的所有权,以便我们安全,那么为什么在“vector_base b " 析构函数无论如何都会在交换完成后释放内存?

I understand the need to explicitly call the destructor in the cases when it must be called because we have something to destruct (eg drop elements) but I fail to see its meaning after the std::move + deallocation of vector_base.我理解在必须调用析构函数的情况下需要显式调用它,因为我们有一些要破坏的东西(例如删除元素),但是在 std::move + vector_base 的释放之后我看不到它的含义。 I read some texts on the net and I'm seeing the destructor call of the moved-from object as an signal (to whom or what?) that the lifetime of the object is over.我在网上阅读了一些文本,我看到从对象的析构函数调用作为一个信号(对谁或什么?)对象的生命周期已经结束。

Please clarify to me what meaningful work remains to be done by the destructor?请向我澄清析构函数还有哪些有意义的工作要做? Thank you!谢谢!

The code snippet below is from here http://www.stroustrup.com/4th_printing3.html下面的代码片段来自这里http://www.stroustrup.com/4th_printing3.html

template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=capacity()) return;                   // never decrease allocation
    vector_base<T,A> b {vb.alloc,size(),newalloc-size()};   // get new space
    uninitialized_move(vb.elem,vb.elem+size(),b.elem);  // move elements
    swap(vb,b);                                 // install new base 
} // implicitly release old space

template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
    using T = Value_type<Out>;      // assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_)
    for (; b!=e; ++b,++oo) {
        new(static_cast<void*>(&*oo)) T{move(*b)};  // move construct
        b->~T();                                // destroy
    }
    return oo;       
}

Moving from an object just means that the moved-from object might donate its guts to live on in another live object shortly before it is [probably] going to die.从一个物体移动只是意味着被移动的物体可能会在它[可能]即将死亡之前不久捐赠它的内脏以在另一个活物体中继续存在。 Note, however, that just because an object donated its guts that the object isn't dead!但是请注意,仅仅因为一个物体捐赠了它的内脏,这个物体并没有死! In fact, it may be revived by another donating object and live on that object's guts.事实上,它可能会被另一个捐赠对象复活并依靠该对象的胆量生存。

Also, it is important to understand that move construction or move assignment can actually be copies!此外,重要的是要了解移动构造或移动分配实际上可以是副本! In fact, they will be copies if the type being moved happens to be a pre-C++11 type with a copy constructor or a copy assignment.事实上,如果要移动的类型恰好是具有复制构造函数或复制赋值的 C++11 之前的类型,它们是副本。 Even if a class has a move constructor or a move assignment it may choose that it can't move its guts to the new object, eg, because the allocators mismatch.即使一个类有一个移动构造函数或一个移动赋值,它也可以选择它不能将其内脏移动到新对象,例如,因为分配器不匹配。

In any case, a moved from object may still have resources or need to record statistics or whatever.在任何情况下,移动的对象可能仍然有资源或需要记录统计信息或其他任何东西。 To get rid of the object it needs to be destroyed.为了摆脱对象,它需要被销毁。 Depending on the class's contracts it may even have a defined state after being moved from and could be put to new use without any further ado.根据类的合同,它甚至可能在被移出后具有定义的状态,并且可以毫不费力地投入新的使用。

In his proposal to implement move semantics through rvalue references , Howard Hinant considered the push for Destructive Move too.通过右值引用实现移动语义的提议中,Howard Hinant 也考虑了对破坏性移动的推动。 But as he pointed in the same article, a move operation basically deals with to objects (source an destination) simultaneously in transition state - even in single threaded applications.但正如他在同一篇文章中指出的那样,移动操作基本上同时处理处于过渡状态的对象(源和目标) - 即使在单线程应用程序中也是如此。 The problem with destructive move is that either source, or destination will experience a state in where derived subpart of an object is constructed while base subpart is destroyed or uninitialized.破坏性移动的问题在于,源或目标将经历这样一种状态,即构造对象的派生子部分,而基础子部分被破坏或未初始化。 This was not possible prior to move proposal, and is not acceptable yet.这在搬迁提案之前是不可能的,现在还不能接受。 So the other choice left was to leave the moved from object in a valid empty state and let the destructor remove the valid empty state.所以剩下的另一个选择是让移动的对象处于有效的空状态,并让析构函数删除有效的空状态。 For many practical purposes, destroying valid empty state is a noop;出于许多实际目的,破坏有效的空状态是无用的; But it's not possible to be generalized for all cases.但不可能对所有情况一概而论。 So, the moved from object is supposed to be either destructed, or assigned(move or copy) to.因此,被移动的对象应该被破坏或分配(移动或复制)到。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM