簡體   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