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是活动的,那么对它的每个可变引用都应该是可以的.

我可以看出当引入线程时可能会出现问题,但为什么即使我在一个线程中完成所有操作,也会被阻止呢?

推荐答案

我如何通过对同一事物的多个可变引用来做坏事(例如分段错误、未定义的行为等)?

我相信,尽管这样做会触发"未定义的行为",但technically Rust编译器不会对&mut个引用使用noalias标志,所以practically说,现在,你可能无法通过这种方式触发未定义的行为.触发的是"实现特定行为",它的行为类似于LLVM的C++.

更多信息请参见Why does the Rust compiler not optimize code assuming that two mutable references cannot alias?.

我可以看出当引入线程时可能会出现问题,但为什么即使我在一个线程中完成所有操作,也会被阻止呢?

this series of blog articles about undefined behavior

在我看来,竞争条件(比如迭代器)并不是你所说的一个很好的例子;在单线程环境中,如果小心,可以避免此类问题.这和创建一个指向无效内存的任意指针并写入它没有什么不同;别这么做.你的情况并不比使用C更糟.

为了理解这里的问题,考虑在发布模式编译时,编译器在执行优化时可以或可能不重新排序语句;这意味着,尽管代码可能以线性顺序运行:

a; b; c;

如果(根据编译器知道的情况)没有逻辑上的理由说明这些语句必须按特定的原子顺序执行,则无法保证编译器在运行时会按该顺序执行它们.我在上面链接的博客的第3部分演示了这如何会导致未定义的行为.

tl;dr:基本上,编译器可以执行各种优化;这些保证会继续使您的程序以确定性的方式运行if and only if您的程序不会触发未定义的行为.

据我所知,Rust compiler currently没有使用许多可能导致此类故障的"高级优化",但不能保证将来不会.引入新的编译器优化并不是一个"突破性的改变".

所以实际上,你现在很可能不太可能仅仅通过可变别名触发实际的未定义行为;但这种限制允许将来进行性能优化.

相关引用:

C FAQ对"未定义行为"的定义如下:

任何事情都有可能发生;该标准没有规定任何要求.程序可能无法编译,或者可能执行不正确(崩溃或默默地生成错误的结果),或者它可能意外地完全按照程序员的意图执行.

Rust相关问答推荐

as操作符如何将enum转换为int?

在执行其他工作的同时,从共享裁判后面的VEC中删除重复项

如何获取Serde struct 的默认实例

从Type::new()调用函数

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

为什么Option类型try块需要类型注释?

为什么rustc会自动降级其版本?

提取指向特征函数的原始指针

使用 Option 来分配?

如何获取模块树?

‘&T as *const T as *mut T’ 在 ‘static mut’ 项目中合适吗?

Rust typestate 模式:实现多个状态?

为什么我不能克隆可克隆构造函数的Vec?

当 T 不是副本时,为什么取消引用 Box 不会抱怨移出共享引用?

Rust 异步和 AsRef 未被发送

Rust,使用枚举从 HashMap 获取值

是否有适当的方法在参考 1D 中转换 2D 数组

TcpStream::connect - 匹配武器具有不兼容的类型

Rustfmt 是否有明确类型的选项?

使用泛型作为关联类型,没有幻像数据