为什么将&T转换为&mut T未定义的行为?

问题描述 投票:0回答:2

我想重新解释对可变引用的不可变引用(在不安全的块中,并独自负责安全检查,但看来我不能使用mem::transmute()来这样做。

let map_of_vecs: HashMap<usize, Vec<_>> = ...;
let vec = map_of_vecs[2];
/// obtain a mutable reference to vec here
  • 我不想将Vec包装到Cell中,因为这会影响使用map_of_vecs的所有其他代码区域,而我只需要一行就可以更改。
  • 我无权访问map_of_vecs
rust
2个回答
3
投票

Rust优化器假设&mut T引用是唯一的。例如,它可能推断出可以重用特定的一块内存,因为存在对该内存的可变引用,但是再也不会对其进行访问。

但是,如果将&T转换为&mut T,则可以为同一数据创建多个可变引用。如果编译器做出此假设,您最终可能会取消引用已经被其他内容覆盖的值。

这只是编译器可能如何利用可变引用是唯一的假设的一个示例。实际上,编译器可以自由使用它认为合适的任何方式使用此信息-可能(并且可能会)在版本之间进行更改。

即使您认为,您也已保证引用没有别名,您也不​​能始终保证您的代码用户不会创建更多引用。即使您认为可以肯定,引用的存在也非常微妙,很容易错过其中的一个。例如,当您调用采用&self的方法时,这就是参考。


1
投票

Rust编译器使用LLVM &Tnoalias属性注释readonly函数参数(前提是T不包含任何UnsafeCell部分)。 noalias属性告诉LLVM,该指针后面的内存只能通过this指针(而不是通过任何其他指针)写入,而readonly属性则告诉LLVM无法对其进行写入通过该指针(但可能还有其他指针)。结合使用,这两个属性允许LLVM优化器假定在执行此功能期间内存完全没有变化,并且可以基于此假设来优化代码。优化程序可能会重新排序指令或删除代码,只有在您确实遵守此合同的情况下,这种方法才可以安全地进行。

转换可能导致不确定行为的另一种方法是针对静态变量:没有UnsafeCell的不可变静态变量将被放置到只读存储器中,因此,如果您实际写入它们,则代码将出现段错误。

对于具有UnsafeCell的参数,编译器不会发出readonly属性,而将包含UnsafeCell的静态变量放入可写内存。

© www.soinside.com 2019 - 2024. All rights reserved.