简体   繁体   中英

Memory deallocation using slice::from_raw_parts_mut and ptr::drop_in_place in rust

I saw a piece of code online that was dropping allocated memory using a combination of std::slice::from_raw_parts_mut() and std::ptr::drop_in_place() . Below is a piece of code that allocates an array of ten integers and then de-allocates it:

use std::{
    alloc::{alloc, Layout},
    ptr::NonNull,
};

fn main() {
    let len: usize = 10;
    let layout: Layout = Layout::array::<i32>(len).unwrap();
    let data: NonNull<i32> = unsafe { NonNull::new(alloc(layout) as *mut i32).unwrap() };

    unsafe {
        std::ptr::drop_in_place(std::slice::from_raw_parts_mut(data.as_ptr(), len));
    }
}

The return type of std::slice::from_raw_parts_mut() is a mutable slice &mut [T] , but the argument of std::ptr::drop_in_place() is *mut T . It seems to me that the conversion happens automatically. I'm pretty sure I'm missing something here since it shouldn't be allowed. Would someone explain what exactly is happening here?

When you write std::slice::from_raw_parts_mut(data.as_ptr(), len) you are building a value of type &mut [i32] .

Then you are passing it to drop_in_place() that is defined more or less as:

fn drop_in_place<T: ?Sized>(to_drop: *mut T)

So you are coercing a &mut [i32] into a *mut T , that is solved in two steps: there is an automatic coercion from reference to pointer , and then T is resolved as [i32] which is the type whose drop is actually called.

(You may think that the automatic coercion from reference to pointer is dangerous and should not be automatic, but it is actually totally safe. What is unsafe is usually what you do with the pointer afterwards. And actually there are a couple of uses of raw pointers that are safe, such as std::ptr::eq or std::ptr::hash ).

Slices implement Drop::drop by simply iterating over the elements and calling drop_in_place in each of them. This is a clever way to avoid writing the loop manually.

But note a couple of things about this code:

  1. drop_in_place will call Drop::drop on every element of the slice, but since they are of type i32 it is effectively a no-op. I guess that your original code uses a generic type.
  2. drop_in_place does not free the memory, for that you need a call to std::alloc::dealloc .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM