Rust Global.dealloc 与 ptr::drop_in_place 与 ManuallyDrop

Mar*_*rer 2 pointers destructor allocation rust

我对 Rust 还比较陌生。我正在研究一些无锁算法,并开始尝试手动管理内存,类似于 C++ new/delete。我注意到在整个标准库组件中有几种不同的方法可以做到这一点,但我想真正了解每种方法的差异和用例。这对我来说是这样的:

ManuallyDrop<Box<T>>将阻止 Box 的析构函数运行。我可以保存指向该元素的原始指针ManuallyDrop,并让实际元素超出范围(通常在 Rust 中会被删除)而不被删除。我可以稍后致电ManuallyDrop::drop(&mut *ptr)手动删除该值。

我还可以取消引用该ManuallyDrop<Box<T>>元素,将原始指针保存到Box<T>,然后调用std::ptr::drop_in_place(box_ptr)。这应该会破坏Box自身并删除堆分配的T.

看看ManuallyDrop::drop实现,看起来它们实际上在做完全相同的事情。由于ManuallyDrop它的成本为零并且仅在其结构中存储一个值,因此上述两种方法有什么区别吗?

我还可以调用std::alloc::Global.dealloc(...),它看起来会在不调用 drop 的情况下释放内存块。因此,如果我在指向 的指针上调用它Box<T>,它将释放堆指针,但不会调用drop,因此T仍然位于堆上。我可以在指向自身的指针上调用它T,这将删除T.

从探索标准库来看,它看起来像是Global.dealloc在实现中被调用 raw_vec以实际删除指向的堆分配数组Vec。这是有道理的,因为它实际上是在尝试删除一块内存。

Rc有一个 drop 实现,大致如下所示:

// destroy the contained object
ptr::drop_in_place(self.ptr.as_mut());

// remove the implicit "strong weak" pointer now that we've
// destroyed the contents.
self.dec_weak();

if self.weak() == 0 {
    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
}
Run Code Online (Sandbox Code Playgroud)

我真的不明白为什么它需要deallocdrop_in_placedealloc添加了哪些内容而drop_in_place没有添加什么?

另外,如果我只是通过执行类似的操作来保存指向堆分配值的原始指针Box::new(5).into_raw(),那么我的指针现在是否控制该内存分配。例如,在我明确调用之前它会保持活动状态吗ptr::drop_in_place()

最后,当我玩这一切时,我遇到了一个奇怪的问题。ManuallyDrop::drop在我的原始指针上运行后ptr::drop_in_place,我尝试println!在指针的取消引用值上运行。有时我会遇到可怕的堆错误,并且测试失败,这正是我所期望的。其他时候,它只是打印相同的值,就好像没有发生滴水一样。我还尝试ManuallyDrop::drop对完全相同的值和相同的事情运行多次。有时是堆错误,有时完全正常,并且打印出相同的值。

这里发生了什么?

rod*_*igo 5

如果您来自 C++,您可以认为drop_in_place手动调用析构函数,以及dealloc调用旧的 C free

它们有不同的用途:

  • drop_in_place只需调用Drop::drop,即可释放您的类型所持有的资源。
  • dealloc释放之前用 分配的指针指向的内存alloc

您似乎认为这drop_in_place也释放了内存,但事实并非如此。我认为您会感到困惑,因为Box<T>包含一个动态分配的对象,因此它的Box::drop实现确实释放了该对象使用的内存,drop_in_place当然,在调用它之后。

这就是您在Rc实现中看到的,首先它调用drop_in_place内部对象的(析构函数),然后释放内存。

drop_in_place如果您连续多次调用会发生什么……好吧,该函数不安全是有原因的:您很可能会得到Uundefined Behaviour。来自文档:

...如果 T 不是Copy,则在调用后使用指向的值drop_in_place可能会导致未定义的行为。

请注意can cause. 我认为完全有可能编写一个允许drop多次调用的类型,但这听起来不是一个好主意。