以下是 The Rust Programming Language chapter on ownership的摘录:
现在考虑以下代码片段:
let v = vec![1, 2, 3]; let mut v2 = v;
第一行为堆栈上的向量对象
v
分配内存 就像上面的x
一样。但除此之外,它还分配 堆上的一些内存用于实际数据([1, 2, 3]
)。 Rust副本 这个堆分配到内部指针的地址,即 放置在堆栈上的矢量对象的一部分(让我们称之为数据 指针)。值得指出(即使有说明显而易见的风险) 向量对象及其数据存在于不同的内存区域中 而不是单个连续的内存分配(由于原因 我们不会在这个时间点进入)。这两部分 vector(堆栈中的一个和堆上的一个)必须同意每个 其他在任何时候都有关于长度,容量, 等
当我们将
v
移动到v2
时,Rust实际上会执行向量的按位复制 将对象v
放入由v2
表示的堆栈分配中。这很浅 copy不会创建包含的堆分配的副本 实际数据。这意味着会有两个指针 向量的内容都指向相同的内存分配 堆。它会违反Rust的安全保障,引入一个 数据争用,如果可以同时访问v
和v2
。例如,如果我们将向量截断为仅两个元素
v2
:v2.truncate(2);
且
v
仍可访问,因为v
我们最终会收到无效的向量 不会知道堆数据已被截断。现在,部分 堆栈上的向量v
与相应的部分不一致 在堆上。v
仍然认为向量中有三个元素 我们很乐意让我们像你一样访问不存在的元素v[2]
可能已经知道这是灾难的秘诀。特别是因为 它可能导致分段错误或更糟糕地允许未经授权 用户从内存中读取他们无权访问的内容。
使用v2
截断向量后,将在堆内存上更新截断值。 v1
仍然看到堆内存,在截断后,它会看到新值。那么为什么这本书会说
且
v
仍然可访问我们最终会出现无效的向量,因为v
不知道堆数据已被截断
答案 0 :(得分:1)
您缺少的是Vec
包含指向堆的指针和len
,或者堆数据的长度。如果v2
截断Vec
,则截断的数据可能已被释放,v1
仍然认为截断的内存仍然是向量的一部分。
答案 1 :(得分:0)
我想我明白了。关键是要知道Rust有这个内部指针,它也是Rust用来定位堆上数据地址的堆栈空间!
如果v2
在堆上更改了这些数据,v2
的内部指针会使用新的数据分配地址进行更新,而v1
的内部指针仍然会引用旧的数据分配地址!