4

我正在实现一个算法,为了保持所需的时间复杂度,我想持有一个指向正在移动的元素的Vec指针Vec

具体来说,是这样的:

fn main() {
    let mut v: Vec<usize> = vec![1, 2, 3];
    let ptr: *mut usize = &mut v[1] as *mut usize;
    let mut u: Vec<usize> = v;
    assert!(ptr == &mut u[1] as *mut usize);
    println!("{}", unsafe { *ptr });
}

实际的代码更复杂,并且涉及一个树状数据结构,其中每个顶点拥有一个Vec子节点。我不是在这里询问编码风格,但我的问题是关于是否可以依靠这段代码来做我认为它做的事情。

由于Vec必须将其内容保存在堆上,并且移动等同memcpy于 Rust,我认为Vec可移动的事实意味着我的代码是合理的(即不是未定义的行为)。这个对吗?

4

1 回答 1

3

你可以这样做:

fn main() {
    let mut v: Vec<usize> = vec![1, 2, 3];
    let ptr: *mut usize = &mut v[1] as *mut usize;
    let mut u: Vec<usize> = v;
    assert!(ptr == &mut u[1] as *mut usize);
    // I copied this from Stack Overflow without reading the surrounding prose 
    println!("{}", unsafe { *ptr });
}

您应该unsafe准确记录该块的安全条件以及您如何维护它们。在这种情况下...

  1. Vec元素是堆分配的

    如果 aVec已分配内存,则它指向的内存在堆上

  2. 您在移动期间没有更改后备分配。这可能是由于对Vec导致调整大小或破坏的任何修改造成的。

  3. 当您尝试使用引用时,不存在对同一元素(包括可能到达同一元素的任何内容)的别名引用。


对于此示例,我只使用索引 ( 1)。对于您的树案例,我会尝试使用索引向量。基准测试,看看是否有明显的差异。

于 2020-08-24T16:04:15.487 回答