Rust 裸指针代码无println!语句时运行结果异常原因咨询
核心问题成因
你的代码出现异常的根本原因是存在未定义行为(Undefined Behavior, UB),看似无关的println!改变运行结果是UB的典型表现。
具体悬垂指针的来源:
- Rust中值发生移动时,其栈上内存地址会变更。你在
Solution::new方法中将Solution实例创建在new的栈帧上,取当前栈上实例的list字段地址赋值给ptr后,又将整个Solution实例作为返回值移动到main的栈帧中,此时new栈帧的内存已经被回收,ptr存储的就是指向无效栈内存的悬垂指针,后续对该指针的所有读写操作都不符合Rust的内存安全规则。 - 有无
println!会改变程序运行时的栈帧布局:保留println!时,悬垂指针指向的内存恰好没有被其他数据覆盖,暂时能读到正确值;注释println!后,对应内存被其他数据覆盖,就会读到异常的垃圾数值。
此外你当前存储*const Option<Box<ListNode>>类型指针的设计本身就不稳定:只要Solution实例本身发生移动,所有指向self.list的指针都会再次变成悬垂状态。
修复方案
推荐直接存储指向堆上ListNode的裸指针,堆上内存的地址不会随结构体移动发生变更,可以彻底规避悬垂问题,参考实现如下:
// Definition for singly-linked list. #[derive(PartialEq, Eq, Clone, Debug)] pub struct ListNode { pub val: i32, pub next: Option<Box<ListNode>> } impl ListNode { #[inline] fn new(val: i32) -> Self { ListNode { next: None, val } } } use rand; use std::ptr::null; struct Solution { list: Option<Box<ListNode>>, ptr: *const ListNode } impl Solution { fn new(head: Option<Box<ListNode>>) -> Self { let ptr = head.as_ref().map(|node| &**node as *const ListNode).unwrap_or(null()); Self { list: head, ptr, } } fn get_random(&mut self) -> i32 { let mut jumps: u8 = rand::random(); unsafe { while jumps > 0 { if let Some(next) = (*self.ptr).next.as_ref() { self.ptr = &**next as *const ListNode; } else { self.ptr = self.list.as_ref().map(|node| &**node as *const ListNode).unwrap(); } jumps -= 1; } return (*self.ptr).val; } } }
内容的提问来源于stack exchange,提问作者wangjun
相关产品推荐
相关产品推荐

