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

cvo*_*ake 24 c++ memory-management move-semantics c++11 explicit-destructor-call

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

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

这是我的不完全理解:移动对象意味着移动对象拥有的资源的所有权被转移到移动对象.移动对象中的剩余部分是一些不需要销毁的内置类型的可能成员,当vector_base b超出范围时(在reserve ()调用之后,它们将被释放)).移动对象中的所有指针都将被置于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;       
}
Run Code Online (Sandbox Code Playgroud)

Die*_*ühl 34

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

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

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

  • 移动的对象就像僵尸,你仍然需要杀死它:) (5认同)
  • @DyP:你的陈述是我多年来一直试图抹黑的声明.移动的对象必须仍然保持其所有不变量.移动对象的客户端唯一可以依赖的是移动的对象处于有效(不变的完整)但未指定的状态.现在,如果您是此类的作者,则可以以任何方式定义其不变量.也许你的类有一个不变量,相当于一个移动的值只能被破坏或分配给. (2认同)
  • @Barry:考虑到你的问题,研究一般`std :: swap`算法的实现.这并不是说"破坏性移动语义"没有用.我敢肯定会的.但如果我不得不在"建设性移动语义"和"破坏性移动语义"之间做出选择,我会选择前者,这正是我们十年前的选择.有关此选择的更多详细信息,请参见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Alternative%20move%20designs. (2认同)