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); }
我想摆脱容量,因为它对我的前端没用;它只是为了让我可以重建我的矢量来释放记忆.
Vec :: shrink_to_fit()很有吸引力,因为它似乎消除了处理容量的需要.不幸的是,它上面的文档并不保证它会使len ==容量,因此我假设在from_raw_parts()期间可能会触发Undefined Behavior.
into_Boxed_slice()似乎有一个保证,它将从docs获得len ==容量,所以我接下来使用它.如果我错了,请纠正我.问题是它似乎不能保证不重新分配.这是一个简单的程序:
fn main() { let mut v = Vec::with_capacity(1000); v.push(100u8); v.push(110); let ptr_1 = v.as_mut_ptr(); let mut Boxed_slice = v.into_Boxed_slice(); let ptr_2 = Boxed_slice.as_mut_ptr(); let ptr_3 = Box::into_raw(Boxed_slice); println!("{:?}. {:?}. {:?}",ptr_1,ptr_2,ptr_3); }
In the playground,它打印:
rustc 1.14.0 (e8a012324 2016-12-16) 0x7fdc9841b000. 0x7fdc98414018. 0x7fdc98414018
如果必须找到新的内存而不是在不造成副本的情况下脱掉额外的容量,这就不好了.
有没有其他方法可以将我的矢量传递到FFI(到C)而不传递容量?似乎into_Boxed_slice()是我需要的,但为什么它涉及重新分配和复制数据?
解决方法
现代内存分配器将在“大小”平板中分离分配,其中每个平板负责处理给定范围的大小.例如:
> 8字节slab:1到8个字节的任何内容
> 16字节slab:从9到16字节的任何内容
> 24字节slab:从17到24字节的任何内容
> ……
当你分配内存时,你要求一个给定的大小,分配器找到正确的slab,从中获取一个块,然后返回你的指针.
当你释放内存时…你怎么期望分配器找到合适的平板?有两种解决方案:
>分配器有办法搜索包含你的内存范围的板,不知何故,它涉及通过板块的线性搜索或某种全局查找表或……
>告诉分配器分配块的大小是多少
这里显而易见的是,C接口(free,realloc)相当低于标准,因此Rust希望使用更有效的接口,即onus在调用者上的接口.
所以,你有两个选择:
>通过容量
>确保长度和容量相等
如您所知,(2)可能需要新的分配,这是非常不受欢迎的. (1)可以通过全程传递容量来实现,也可以在某个时候存储容量,然后在需要时检索它.
而已.你必须评估你的权衡.