rust - 拆分 `Vec`

标签 rust unsafe borrow-checker

我正在尝试编写一个用于解析的小缓冲区,这样我就可以在解析它们时从前端提取记录,理想情况下不制作任何副本,而只是将缓冲区前端 block 的所有权转移为我跑。这是我的实现:

struct BufferThing {
    buf: Vec<u8>,
}

impl BufferThing {
    fn extract(&mut self, size: usize) -> Vec<u8> {
        assert!(size <= self.buf.len());
        let remaining: usize = self.buf.len() - size;
        let ptr: *mut u8 = self.buf.as_mut_ptr();

        unsafe {
            self.buf = Vec::from_raw_parts(ptr.offset(size as isize), remaining, remaining);
            Vec::from_raw_parts(ptr, size, size)
        }
    }
}

这会编译,但会在开始运行时出现 信号:11,SIGSEGV:无效内存引用 的 panic 。这与 the Nomicon 中的示例代码基本相同。 ,但我正在尝试在 Vec 上执行此操作,并且我正在尝试拆分一个字段而不是对象本身。

是否可以在不复制其中一个 Vec 的情况下执行此操作?是否有 Nomicon 或其他文档的某些部分解释了为什么我要炸掉 unsafe block 中的所有内容?

最佳答案

不幸的是,这不是内存分配器的工作方式。这在过去可能是可行的,当时内存非常宝贵,但今天的分配器更注重速度而不是内存保存。

内存分配器的一个常见实现是使用 slab。基本上,它是:

struct Allocator {
    less_than_32_bytes: List<[u8; 32]>,
    less_than_64_bytes: List<[u8; 64]>,
    less_than_128_bytes: List<[u8; 128]>,
    less_than_256_bytes: List<[u8; 256]>,
    less_than_512_bytes: List<[u8; 512]>,
    ...
}

当你请求96字节时,它从less_than_128_bytes中取一个元素.

当您释放该元素时,它会释放所有 元素,而不仅仅是前 N 个字节,并且整个 block 现在都可以重复使用。 block 内的任何指针现在都是悬空的,不应取消引用。

此外,尝试释放 block 中间的指针只会混淆分配器:它不会找到它,因为约定是您按 block 的第一个字节寻址。

您使用 unsafe 违反了契约(Contract)代码,BOOM


我提出的解决方案很简单:

  • 使用单个 Vec<u8>包含要解析的整个缓冲区
  • 在这个 Vec 中使用切片用于解析

Rust 将检查生命周期,因此您的切片不能超过缓冲区,并且进一步切片(s[..offset]s[offset..])不会分配。


如果你不介意一个分配,那就是 Vec::split_off 它分配一个新的 Vec足够大的 split 部分。

关于rust - 拆分 `Vec`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42163975/

相关文章:

visual-studio-code - VSCode调试无法显示引用值

thread-safety - 我如何保证一个没有实现 Sync 的类型实际上可以在线程之间安全地共享?

c# - 我可以在 VB.NET 中使用带有不安全代码的 C# dll 吗?

c# - 为什么 'stackalloc' 关键字不适用于属性?

rust - 了解循环中的不可变借用

Rust:将值移出选项并压入堆栈

rust - 从 HashMap 或 Vec 返回引用会导致借用超出其所在范围?

rust - 如何指定 AsRef 的生命周期?

error-handling - 如何使用自定义结构实现错误

rust - 我可以创建一个指向堆栈对象的拥有指针吗