为什么在std :: move之后需要调用析构函数?

时间:2013-12-14 22:34:10

标签: c++ memory-management c++11 move-semantics explicit-destructor-call

在C ++编程语言第4版中,有一个向量实现的示例,请参阅消息末尾的相关代码。

uninitialized_move()通过从旧内存区域移动新T对象,将其初始化到新内存区域。然后它调用原始T对象上的析构函数,即移动对象。在这种情况下,为什么析构函数需要调用?

以下是我的不完全理解:移动对象意味着移动对象拥有的资源的所有权将转移到移动对象。移动对象中的剩余部分是内置类型的一些可能成员,不需要销毁,当vector_base b超出范围时(在 reserve()内部,它们将被释放) ,在 swap()调用之后)。移动对象中的所有指针都将被置于nullptr或者使用某种机制来删除这些资源上移动对象的所有权以便我们安全,那么为什么在“vector_base b”时调用耗尽对象上的析构函数“在交换完成后,析构函数还是会释放内存吗?

我理解在必须调用析构函数的情况下需要显式调用析构函数,因为我们有一些东西需要破坏(例如drop元素),但是在vector_base的std :: move + deallocation之后我看不到它的含义。我在网上阅读了一些文本,我看到被移动对象的析构函数调用作为一个信号(对谁或什么?)对象的生命周期结束。

请向我澄清析构函数还有哪些有意义的工作要做?谢谢!

下面的代码段来自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;       
}

1 个答案:

答案 0 :(得分:31)

从一个对象移动只是意味着移动的对象可能捐赠它的内容,以便在它[可能]死亡之前不久存在于另一个活动对象中。但请注意,仅仅因为一个物体捐赠了它的内脏,物体就没死了!事实上,它可能会被另一个捐赠对象复活并活在那个对象的胆量上。

此外,重要的是要了解移动构造或移动分配实际上可以复制!实际上,如果被移动的类型恰好是具有复制构造函数或复制赋值的C ++ 11之前的类型,则它们成为副本。即使一个类具有移动构造函数或移动赋值,它也可以选择它不能将其内容移动到新对象,例如,因为分配器不匹配。

在任何情况下,从对象移动可能仍然有资源或需要记录统计信息或其他任何内容。要摆脱它需要被摧毁的对象。根据班级的合同,它可能在被移出之后具有已定义的状态,并且可以在没有任何进一步的麻烦的情况下被用于新的用途。