Vector – what is the correct way to convert VEC to FFI without reallocation?
I need to pass an element VEC in the FFI Through the experiment, I found some interesting ideas I started to give the FFI all 3: PTR, len and capacity so that I could rebuild VEC and destroy it later:
let ptr = vec.as_mut_ptr(); let len = vec.len(); let cap = vec.capacity(); mem::forget(vec); extern_fn(ptr,len,cap); // ... pub unsafe extern "C" fn free(ptr: *mut u8,len: usize,cap: usize) { let _ = Vec::from_raw_parts(ptr,cap); }
I want to get rid of capacity because it's useless for my front end; It's just so that I can reconstruct my vector to release my memory
Vec :: shrink_ to_ Fit () is attractive because it seems to eliminate the need for processing capacity Unfortunately, the documentation above it does not guarantee that it will make len = = capacity, so I assume that it is in from_ raw_ Undefined behavior may be triggered during parts()
into_@ R_ 42_ 2419@ed_slice () seems to have a guarantee that it will get len = = capacity from docs, so I'll use it next If I am wrong, please correct me The problem is that it does not seem to guarantee against redistribution This is a simple procedure:
fn main() { let mut v = Vec::with_capacity(1000); v.push(100u8); v.push(110); let ptr_1 = v.as_mut_ptr(); let mut @R_42_2419@ed_slice = v.into_@R_42_2419@ed_slice(); let ptr_2 = @R_42_2419@ed_slice.as_mut_ptr(); let ptr_3 = @R_42_2419@::into_raw(@R_42_2419@ed_slice); println!("{:?}. {:?}. {:?}",ptr_1,ptr_2,ptr_3); }
In the playground, it prints:
rustc 1.14.0 (e8a012324 2016-12-16) 0x7fdc9841b000. 0x7fdc98414018. 0x7fdc98414018
It's bad if you have to find new memory instead of taking off the extra capacity without causing a copy
Is there any other way to pass my vector to FFI (to c) without passing capacity? It seems that into_@ R_ 42_ 2419@ed_slice () is what I need, but why does it involve reallocating and replicating data?
Solution
The reason is relatively simple
Modern memory allocators separate allocations in "size" plates, where each plate is responsible for handling a given range of sizes For example:
>8-byte slab: anything from 1 to 8 bytes > 16 byte slab: anything from 9 to 16 bytes > 24 byte slab: anything from 17 to 24 bytes >
When you allocate memory, you ask for a given size. The allocator finds the correct slab, gets a block from it, and then returns your pointer
When you free memory... How do you expect the allocator to find the right tablet? There are two solutions:
>The allocator has a way to search the board containing your memory range. Somehow, it involves a linear search through the board or some kind of global lookup table or... > tell the allocator what the size of the allocated block is
It is obvious that the C interface (free, realloc) is quite below the standard, so rust wants to use a more effective interface, that is, onus's interface on the caller
So you have two choices:
>Ensure that the length and capacity are equal through capacity >
As you know, (2) new assignments may be required, which is very unpopular (1) It can be realized by transferring capacity all the way, or it can store capacity at a certain time and retrieve it when needed
nothing more. You must evaluate your trade - offs