繁体   English   中英

rust 移动语义实际上是如何工作的

[英]how does rust move semantics actually work

在我写了一些代码并阅读了一些文章之后,我对 rust 中的移动语义有点困惑,我认为值移动后,它应该被释放,memory 应该无效。 所以我尝试写一些代码来作证。

第一个例子

#[derive(Debug)]
struct Hello {
    field: u64,
    field_ptr: *const u64,
}

impl Hello {
    fn new() -> Self {
        let h = Hello {
            field: 100,
            field_ptr: std::ptr::null(),
        };
        h
    }

    fn init(&mut self) {
        self.field_ptr = &self.field as *const u64;
    }
}
fn main(){
    let mut h = Hello::new();
    h.init();
    println!("=================");
    println!("addr of h: ({:?}) \naddr of field ({:?})\nfield_ptr: ({:?}) \nptr value {:?}", &h as *const Hello, &h.field as *const u64, h.field_ptr, unsafe {*h.field_ptr});

    let c = &h.field as *const u64;
    let e = &h as *const Hello;
    let a = h;
    let d = &a.field as *const u64;

    println!("=================");
    println!("addr of a: ({:?}) \naddr of field ({:?})\nfield_ptr: ({:?}) \nptr value {:?}", &a as *const Hello, &a.field as *const u64, a.field_ptr, unsafe {*a.field_ptr});
    println!("=================");
    println!("addr of c {:?}\nvalue {:?}", c, unsafe {*c});
    println!("addr of d {:?}\nvalue {:?}", d, unsafe {*d});
    println!("addr of e {:?}\nvalue {:?}", e, unsafe {&*e});
}

上面代码的结果是

=================
addr of h: (0x7ffee9700628) 
addr of field (0x7ffee9700628)
field_ptr: (0x7ffee9700628) 
ptr value 100
=================
addr of a: (0x7ffee9700720) 
addr of field (0x7ffee9700720)
field_ptr: (0x7ffee9700628) 
ptr value 100
=================
addr of c 0x7ffee9700628
value 100
addr of d 0x7ffee9700720
value 100
addr of e 0x7ffee9700628
value Hello { field: 100, field_ptr: 0x7ffee9700628 }

所以,我创建了一个自引用结构Hello并使 field_ptr 指向 u64 字段,并使用原始点来保存结构的地址和字段的地址,然后将 h 移动到 a 以使 h 变量无效,但是我仍然可以通过原始点获取IMO不应该存在的原始变量的值吗?

第二个例子

struct Boxed {
    field: u64,
}
fn main(){

   let mut f = std::ptr::null();
    {
        let boxed = Box::new(Boxed{field: 123});
        f = &boxed.field as *const u64;
    }
    println!("addr of f {:?}\nvalue {:?}", f, unsafe {&*f});
}

结果

addr of f 0x7fc1f8c05d30
value 123

我创建了一个盒装值并在使用原始点保存它的地址后将其删除,我仍然可以通过原始点读取它的字段值。

所以我的困惑是

  1. rust 中的移动实际上是一个 memcpy 吗? 原始变量只是被编译器“隐藏”了吗?
  2. rust 什么时候真正释放堆上的变量 memory? (第二个例子)

谢谢

我读过的内容Rust 如何提供移动语义?

那么你的output的第一块应该清楚了吧? 该结构的地址只是 memory 的第一位,该结构位于 memory 中,这与其第一个字段的地址相同。

现在是你的第二个街区。 您正在获取结构中的一些原始指针,然后通过let a = h移动结构。

它的作用是:在堆栈上我们现在有一个新变量a ,它是变量h的旧堆栈布局的 memory 副本。 这就是aa.field都有新地址的原因。 当然,原始指针仍然指向旧的h.field地址,这就是您仍然可以访问该数据的原因。

请注意,您只能通过unsafe块执行此操作,因为您所做的是不安全的。 不能保证您的字段指针指向的任何内容都将保持有效。

如果您删除所有unsafe结构的使用,将无法通过h.field a.field

同样的想法适用于第二个例子。 如果您不使用原始指针和不安全的块,您将无法获得丢弃的东西,那是因为这段代码非常可疑。 在您的简单示例中,它仍然有效,因为 Rust 不只是前面的 go 和加扰已丢弃的值的 memory。 除非您程序中的其他内容重新调整了 memory 的用途,否则它将保持原样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM