下面这段代码:
use std::cell::UnsafeCell;
const UNSAFE_CELL: UnsafeCell<i32> = UnsafeCell::new(10);
fn main() {
let local_unsafe_cell = UnsafeCell::new(10);
unsafe {
let x = UNSAFE_CELL.get();
println!("x = {}", *x);
let local_x = local_unsafe_cell.get();
println!("local_x = {}", *local_x);
}
}
假如使用Debug mode去运行它的话,那么表现良好,输出都是10,但是使用release mode去运行它的话,对于UNSAFE_CELL的值的获取就完全是UB,这是为什么?
1
共 3 条评论, 1 页
评论区
写评论const常量属于一种“值”类型,类似字面量值用法。
之所以你这里没给你提示,是因为你调用的是
UnsafeCell::get
返回的是*mut T
,这里实际上返回的是个无效指针(因为直接调用只在方法执行期间有效),当前稳定版rust对指针的使用安全性需要使用者自行保证。指针类型的溯源规则目前应该是还不稳定,所以如第一位老哥说的需要打开nightly才能看到编译器警告。如果你的代码调用改成
let x: &mut T = UNSAFE_CELL.get_mut()
,立马你就能看到编译器的错误信息了。因为引用的生命周期和借用检查器不允许出现无效引用类型,并且会提示你该常量值在调用后即会drop。关于指针溯源(Provenance)规则,目前是还不完善的,我之前看的是rustdoc文档中的
std::ptr
模块文档,感兴趣的话可以看下const不要想象成一个static的那种变量,应该类比成c里#define类的东西。
UNSAFE_CELL 是个 const,所以
let x = UNSAFE_CELL.get()
就是let x = UnsafeCell::new(10).get()
,如果你开 nightly,就会得到一个很详细的 warning:不过回到 stable 就看不到,开 clippy 也没有,不知道下个版本会不会加上。