在C++编程语言第4版中有一个向量实现的例子,请参阅消息末尾的相关代码。
uninitialized_move()通过将新T对象从旧内存区域移到新内存区域来初始化它们。然后调用原始T对象上的析构函数,即moved from对象。为什么在这种情况下必须调用析构函数?
以下是我的不完全理解:移动对象意味着被移动对象所拥有的资源的所有权--从对象转移到移动对象--转移到对象。moved from对象中的剩余部分可能是不需要销毁的内置类型的一些成员,当vector_base b超出作用域时(在reserve()中,在交换()调用之后),它们将被解除分配。移动对象中的所有指针--从对象到nullptr,或者使用某种机制将迁移的所有权从这些资源上删除--为了安全起见,那么当"vector_base b“析构函数完成交换后,为什么要调用耗尽对象上的析构函数呢?
在必须调用析构函数的情况下,我理解显式调用析构函数的必要性,因为我们有一些要销毁的东西(例如,drop元素),但是我看不到它在vector_base的std::move +de配之后的含义。我在网上读到了一些信息,我看到了移动对象的析构函数调用--从对象变成一个信号(对谁或什么?)对象的生命周期已经结束。
请向我说明,破坏者还有哪些有意义的工作要做?谢谢!
下面的代码片段来自这里,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;
}发布于 2013-12-14 22:40:14
从一个物体上移动仅仅意味着被移动的物体可能会捐出它的内脏在另一个活的物体中生存,不久它可能会死去。但是,请注意,仅仅因为一个对象捐赠了它的内脏,这个对象就没有死!事实上,它可能会被另一个捐赠对象复活,并生活在该物体的内脏上。
另外,重要的是要理解移动构造或移动分配实际上可以是副本!实际上,如果要移动的类型恰好是带有副本构造函数或副本赋值的预C++11类型,则它们将是副本。即使一个类有一个移动构造函数或一个移动赋值,它也可能选择它不能将其内部移动到新对象,例如,因为分配程序不匹配。
在任何情况下,移出对象可能仍然有资源或需要记录统计数据或其他任何东西。为了摆脱这个物体,它需要被销毁。根据类的契约,它甚至可能在被移出之后具有一个定义的状态,并且可以在不需要进一步修改的情况下被用于新的用途。
发布于 2022-06-10 12:24:18
在向通过rvalue引用实现移动语义提出的建议中,霍华德·希南特( Howard )也考虑了推动破坏性举措()。但正如他在同一篇文章中所指出的,移动操作基本上是在过渡状态下同时处理对象(源是目标)--甚至在单线程应用程序中。破坏性移动的问题是,源或目标都将经历一种状态,在这种状态下,对象的派生子部分被构造,而基子部分被破坏或未初始化。在提出提案之前,这是不可能的,也是不可接受的。因此,剩下的另一个选择是将moved对象保持为有效的空状态,并让析构函数删除有效的空状态。在许多实际用途中,销毁有效的空状态是一个节点,但不可能对所有情况进行推广。因此,从对象移出的对象应该被销毁,或者分配(移动或复制)给。
https://stackoverflow.com/questions/20589025
复制相似问题