rust - 引用和 Box<T> 在内存中的表示方式有什么区别?

标签 rust

我试图了解如何引用和 Box<T>工作。让我们考虑一个代码示例:

fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

在我的想象中,Rust 将内存中的值保存为:

enter image description here

考虑带有 Box<T> 的第二个代码片段:
fn main() {
    let x = 5;
    let y = Box::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

怎么样x将存储在 Box ?内存是什么样子的?

以上示例来自 Treating Smart Pointers Like Regular References with the Deref Trait .对于第二个例子,本书将其解释为:

The only difference between Listing 15-7 and Listing 15-6 is that here we set y to be an instance of a box pointing to the value in x rather than a reference pointing to the value of x.



是否意味着y在框中直接指向值 5 ?

最佳答案

您的简单案例图很好,尽管在您使用 5 时可能不清楚对于值和地址。我搬家了y在我的图表中,以防止任何混淆。
Box<T> 的内存是什么样的? ?
Box的等效图看起来很相似,但添加了堆:

    Stack

     ADDR                    VALUE
    +------------------------------+
x = |0x0001|                     5 |
y = |0x0002|                0xFF01 |
    |0x0003|                       |
    |0x0004|                       |
    |0x0005|                       |
    +------------------------------+

    Heap

     ADDR                    VALUE
    +------------------------------+
    |0xFF01|                     5 |
    |0xFF02|                       |
    |0xFF03|                       |
    |0xFF04|                       |
    |0xFF05|                       |
    +------------------------------+

(请参阅下面有关此图的迂腐注释)
Box已经为我们在堆中分配了足够的空间,地址是 0xFF01 .然后将该值从堆栈移动到堆上。

Does it mean that y in the box points directly



它不是。 y持有指向 Box 分配的数据的指针.它必须这样做才能在 Box 时释放分配的内存。超出范围。

您正在阅读的这一章的重点是 Rust 将透明地取消引用 Box对你来说,所以你通常不需要关心这个事实。

也可以看看:
  • Do I need to Box child structs of a Boxed struct to get everything on the heap?
  • What is the difference between Vec<i32> and Vec<Box<i32>>?
  • Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
  • What are Rust's exact auto-dereferencing rules?
  • How do I get an owned value out of a `Box`?

  • 内存有什么区别?

    这可能会让你的大脑有点弯曲!

    查看两个示例的堆栈,有 不是 两种情况之间确实存在差异 - 引用和 Box作为指针存储在堆栈中。唯一的区别在于代码,它知道根据它是引用还是 Box 以不同的方式处理堆栈上的值。 .

    事实上,这适用于 Rust 中的一切!对计算机来说,它只是位,程序二进制中编码的结构是唯一将一个字节块与另一个字节块区分开来的东西。

    为什么是 x移至 Box 后仍在堆栈中?

    细心的读者会注意到我留下了值5x在堆栈上。有两个相关的原因:
  • 这实际上就是内存中发生的事情。程序通常不会“重置”它们完成的值,因为这将是不必要的开销。 Rust 通过将变量标记为已移动并禁止访问已移动的变量来避免问题。
  • 在这种情况下,i32工具Copy ,这意味着可以在移动后访问该值。编译器实际上会允许我们继续访问 x .如果 x,这将不是真的是未实现的类型 Copy ,例如 StringBox .

  • 也可以看看:
  • Why does "move" in Rust not actually move?
  • How does Rust move stack variables that are not Copyable?
  • How does Rust provide move semantics?
  • What are move semantics in Rust?

  • 迂腐图笔记
  • 这张图是不按比例 .安 i32占用 4 个字节,指针/引用占用平台相关的字节数,但假设所有内容的大小都相同更简单。
  • 栈通常从高地址开始向下增长,而堆从低地址开始向上增长。
  • 关于rust - 引用和 Box<T> 在内存中的表示方式有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59897489/

    相关文章:

    rust - 如何修复 `` Entirely Too Many Lists'' 第 2 章中损坏的 use 语句?

    rust - 有没有办法在不重复变量名的情况下将命名参数传递给格式宏?

    callback - 奇怪的回调调用语法(需要解释)

    rust - 是否可以在 Rust 中返回借用或拥有的类型?

    struct - 在不克隆的情况下将一个结构数组映射到Rust中的另一个结构数组

    generics - 如果我在函数内部创建引用,如何将泛型类型与需要生命周期参数的特征绑定(bind)?

    rust - Cargo 是否将 semver 与 Git 标签一起使用?

    rust - 是否可以让 wasm-bindgen 忽略 impl 中的某些公共(public)功能?

    rust - 如何更改此函数的返回类型?

    linux - 无法从 Rust 应用程序中的 Serde 引起的回溯中跟踪错误