【问题标题】:Structs with slices pointing to data in themselves带有指向自身数据的切片的结构
【发布时间】:2015-02-02 08:42:37
【问题描述】:

我有一个结构

struct Foo<'a> {
    buf: [u8, ..64],
    slice: &'a [u8]
}

切片应该指向结构的buf 字段。有没有办法构造这样的结构?比如:

impl<'a> Foo<'a> {
    fn new() -> Foo<'a> {
        Foo {
            buf: [0, ..64],
            slice: ???? /* I don't know what to write here */
    }
}

如果我尝试执行以下操作,借用检查器会抱怨(正确),因为切片的生命周期将比结构短。

impl<'a> Foo<'a> {
    fn new() -> Foo<'a> {
        let buf = [0, ..64];
        Foo {
            buf: buf,
            slice: buf.slice_from(0)
        }
    }
}

我意识到对于这种简单的情况,我可以保留偏移量并手动调用切片函数:

struct Foo {
    buf: [u8, ..64],
    slice_from: uint,
    slice_to: uint
}

但是,这个问题只是对拥有数据并引用相同数据的结构的更一般用例的简化,我想知道在 Rust 中这是否可能(以安全的方式)。

【问题讨论】:

标签: rust


【解决方案1】:

不,你不能安全地做到这一点,因为通常这样的结构是不可移动的。假装它是可能的,你可以创建这样的结构:

let foo = Foo {
    buf: [0, ..64],
    slice: obtain_slice_somehow()
};

slice 字段现在是buf 字段的切片,特别是,它包含指向当前位于堆栈上的buf 的指针。现在将foo 放入一个盒子并从函数中返回:

return Box::new(foo);

foo 值现在被移动到堆中,并且函数退出,释放它的堆栈内存。但是slice指针没有调整指向堆,因为一般情况下是不可能的,所以就悬空了,违反了内存安全。

【讨论】:

  • 我明白了。但是,如果 buf 是 Vec 怎么办?然后指针将始终在堆上,即使 foo 被移动也不会变得无效。
  • 我刚刚意识到 vec 当然可以随着它的增长而重新分配,导致切片中的旧指针变得无效。但是,似乎可以通过这样做来欺骗借用检查器。不过,我可能会添加另一个与此相关的问题。
  • @dnaq,我怀疑是否有可能欺骗借用检查器 :) 如果你能做到,那肯定是 rustc 中的一个错误。
  • 我能够欺骗借用检查器,错误报告是here,相关的reddit帖子是here
猜你喜欢
  • 2015-02-21
  • 1970-01-01
  • 2015-07-04
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多