I'm relatively new to Rust. I was working on some lock-free algorithms, and started playing around with manually managing memory, something similar to C++ new/delete. I noticed a couple different ways that do this throughout the standard library components, but I want to really understand the differences and use cases of each. Here's what it seems like to me:
ManuallyDrop<Box<T>>
will prevent Box's destructor from running. I can save a raw pointer to the ManuallyDrop
element, and have the actual element go out of scope (what would normally be dropped in Rust) without being dropped. I can later call ManuallyDrop::drop(&mut *ptr)
to drop this value manually.
I can also dereference the ManuallyDrop<Box<T>>
element, save a raw pointer to just the Box<T>
, and later call std::ptr::drop_in_place(box_ptr)
. This is supposed to destroy the Box
itself and drop the heap-allocated T
.
Looking at the ManuallyDrop::drop
implementation, it looks those are literally doing the exact same thing. Since ManuallyDrop
is zero cost and just stores a value in it's struct, is there any difference in the above two approaches?
I can also call std::alloc::Global.dealloc(...)
, which looks like it will deallocate the memory block without calling drop. So if I call this on a pointer to Box<T>
, it'll deallocate the heap pointer, but won't call drop
, so T
will still be lying around on the heap. I could call it on a pointer to T
itself, which will remove T
.
From exploring the standard library, it looks like Global.dealloc
gets called in the raw_vec
implementation to actually remove the heap-allocated array that Vec
points to. This makes sense, since it's literally trying to remove a block of memory.
Rc
has a drop implementation that looks roughly like this:
// 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()));
}
I don't really understand why it needs both the dealloc
and the drop_in_place
. What does the dealloc
add that the drop_in_place
doesn't do?
Also, if I just save a raw pointer to a heap-allocated value by doing something like Box::new(5).into_raw()
, does my pointer now control that memory allocation. As in, will it remain alive until I explicitly call ptr::drop_in_place()
?
Finally, when I was playing with all this, I ran into a strange issue. After running ManuallyDrop::drop
or ptr::drop_in_place
on my raw pointer, I then tried running println!
on the pointer's dereferenced value. Sometimes I get a scary heap error and my test fails, which is what I would expect. Other times, it just prints the same value, as if no drops happened. I also tried running ManuallyDrop::drop
multiple times on the exact same value, and same thing. Sometimes a heap error, sometimes totally fine, and the same value prints out.
What is happening here?
If you come from C++, you can think of drop_in_place
as calling the destructor manually, and dealloc
as calling old C free
.
They serve different purposes:
drop_in_place
just calls Drop::drop
, that releases the resources held by your type. dealloc
frees the memory pointed to by a pointer, previously allocated with alloc
. You seem to think that drop_in_place
also frees the memory, but that is not the case. I think your confusion arises because Box<T>
contains a dynamically allocated object, so its Box::drop
implementation does release the memory used by that object, after calling its drop_in_place
, of course.
That is what you see in the Rc
implementation, first it calls the drop_in_place
(destructor) of the inner object, then it releases the memory.
About what happens if you call drop_in_place
several times in a row... well, the function is unsafe for a reason: you most likely get Uundefined Behavior . From the docs:
...if T is not
Copy
, using the pointed-to value after callingdrop_in_place
can cause undefined behavior.
Note the can cause
. I think it is perfectly possible to write a type that allows calling drop
several times, but it doesn't sound like such a good idea.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.