以下是The Rust Programming Language 关于所有权一章的摘录:
现在考虑以下代码片段:
let v = vec![1, 2, 3]; let mut v2 = v;
第一行
v
像上面一样为堆栈上的向量对象分配内存x
。但除此之外,它还在堆上为实际数据分配一些内存([1, 2, 3]
)。Rust 将此堆分配的地址复制到一个内部指针,该指针是放置在堆栈上的向量对象的一部分(我们称之为数据指针)。值得指出(即使冒着说明显而易见的风险)向量对象及其数据存在于单独的内存区域中,而不是单个连续的内存分配(由于我们目前不会讨论的原因) . 向量的这两个部分(堆栈上的一个和堆上的一个)在长度、容量等方面必须始终相互一致。
当我们转到
v
时v2
,Rust 实际上将向量对象按位复制v
到由 表示的堆栈分配中v2
。这个浅拷贝不会创建包含实际数据的堆分配的副本。这意味着将有两个指向向量内容的指针,它们都指向堆上的相同内存分配。如果一个人可以同时访问两者v
,就会通过引入数据竞争来违反 Rust 的安全保证v2
。例如,如果我们通过以下方式将向量截断为两个元素
v2
:v2.truncate(2);
并且
v
仍然可以访问,我们最终会得到一个无效的向量,因为v
不知道堆数据已被截断。现在,v
堆栈上的向量部分与堆上的相应部分不一致。v
仍然认为向量中有三个元素,并且很乐意让我们访问不存在的元素v[2]
,但是您可能已经知道这是灾难的根源。特别是因为它可能导致分段错误或更糟的是允许未经授权的用户从他们无权访问的内存中读取。
使用 截断向量后v2
,将在堆内存上更新截断的值。v1
仍然看到堆内存,截断后,它看到了新值。那为什么书上说
并且
v
仍然可以访问,我们最终会得到一个无效的向量,因为v
不知道堆数据已被截断