Rust 不允许这种代码,因为它不安全:
fn main() {
let mut i = 42;
let ref_to_i_1 = unsafe { &mut *(&mut i as *mut i32) };
let ref_to_i_2 = unsafe { &mut *(&mut i as *mut i32) };
*ref_to_i_1 = 1;
*ref_to_i_2 = 2;
}
我怎么能做坏事(e.g.分段错误、未定义的行为等)以及对同一事物的多个可变引用?
我能看到的唯一可能的问题来自数据的生命周期。在这里,如果i
还活着,对它的每个可变引用都应该没问题。
我可以看到引入线程时可能会出现问题,但为什么即使我在一个线程中完成所有操作,它也会被阻止?
C++ 程序(甚至 Java 程序)中一个非常常见的陷阱是在迭代集合时修改集合,如下所示:
for (it: collection) {
if (predicate(*it)) {
collection.remove(it);
}
}
对于 C++ 标准库集合,这会导致未定义的行为。也许迭代会一直工作,直到到达最后一个条目,但最后一个条目将取消引用悬空指针或读取数组的末尾。也许集合底层的整个数组将被重新定位,并且它会立即失败。也许它在大多数情况下都有效,但如果在错误的时间发生重新分配,则会失败。在大多数 Java 标准集合中,根据语言规范,这也是未定义的行为,但集合往往会抛出异常ConcurrentModificationException
- 即使您的代码正确,也会导致运行时成本的检查。这两种语言都无法在编译过程中检测到错误。
这是并发引起的数据争用的常见示例,即使在单线程环境中也是如此。并发不仅仅意味着并行性:它还意味着嵌套计算。在 Rust 中,这种错误是在编译期间检测到的,因为迭代器对集合具有不可变的借用,因此在迭代器处于活动状态时无法更改集合。
一个更容易理解但不太常见的示例是向函数传递多个指针(或引用)时的指针别名。一个具体的例子是将重叠的内存范围传递给memcpy
代替memmove
。实际上,Rust's memcpy相等的 is unsafe
也是如此,但那是因为它需要指针而不是引用。链接页面显示了如何制作一个安全的swap使用可变保证的函数参考从来没有别名。
引用别名的一个更人为的示例如下:
int f(int *x, int *y) { return (*x)++ + (*y)++; }
int i = 3;
f(&i, &i); // result is undefined
您无法在 Rust 中编写类似的函数调用,因为您必须对同一变量进行两次可变借用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)