list - 如何在这个简单的双向链表实现中修复 SIGSEGV?
问题描述
SIGSEGV
运行此代码时出现错误。
代码编译,调试器显示指针中的随机地址。
use std::ptr;
pub struct List<T> {
head: *mut Node<T>,
tail: *mut Node<T>,
}
struct Node<T> {
data: Option<T>,
next: *mut Node<T>,
prev: *mut Node<T>,
}
impl<T> List<T> {
pub fn new() -> Self {
Self {
head: ptr::null_mut(),
tail: ptr::null_mut(),
}
}
pub fn add_tail(&mut self, data: T) {
let mut new_node = Box::new(Node {
data: Some(data),
next: ptr::null_mut(),
prev: ptr::null_mut(),
});
let new_node_ptr: *mut Node<T> = &mut *new_node;
if self.tail.is_null() {
self.head = new_node_ptr;
} else {
new_node.next = self.tail;
unsafe {
(*self.tail).prev = new_node_ptr;
}
}
self.tail = new_node_ptr;
}
pub fn remove_tail(&mut self) -> Option<T> {
if self.tail.is_null() {
None
} else {
let old_tail_ptr = self.tail;
unsafe {
if (*old_tail_ptr).next.is_null() {
self.tail = ptr::null_mut();
self.head = ptr::null_mut();
} else {
let new_tail_ptr = (*old_tail_ptr).next;
(*old_tail_ptr).next = ptr::null_mut();
(*new_tail_ptr).prev = ptr::null_mut();
self.tail = new_tail_ptr;
}
(*old_tail_ptr).data.take()
}
}
}
}
我的测试添加了十个整数0..9
,然后它们弹出它们。在第二次流行音乐中,我得到
信号:11,SIGSEGV:无效的内存引用。
解决方案
以下将修复错误。在add_tail
:
- 替换
let new_node_ptr: *mut Node<T> = &mut *new_node;
为let new_node_ptr = Box::into_raw(new_node);
- 替换
new_node.next = self.tail
为(*new_node_ptr).next = self.tail;
- 包含
(*new_node_ptr).next = self.tail;
在unsafe
块中
该错误是由于错误地从 Box 获取底层指针。
之后let new_node_ptr: *mut Node<T> = &mut *new_node;
Box 继续管理 指向的内存new_node_ptr
。在块结束时,Box 自动释放内存,留下new_node_ptr
悬空。
要获得具有手动内存管理的指针并从 Box 释放对内存的控制,请使用Box::into_raw
而不是&mut *
.
推荐阅读
- kotlin - 具有 2 种视图类型的 kotlin recyclerview
- vue.js - 如何使用地图过滤器?
- azure - 如何在 Azure Devops 上添加新字段并继承旧(前身)字段的值?
- sql-server - 完全独立的 RDLC 报告
- sensenet - 如何通过 API-Sensenet 获取登录的用户角色
- android - mpandroidChart 如何绘制零线?
- c# - 当 `RoutePrefix` 或 `Route` 属性未使用时,获取所有路由列表 (ASP.NET)
- python - 在 Dash plotly 中清除下拉列表时无法显示图形
- mysql - 如何选择今天日期介于开始日期和结束日期之间的行
- python - PySpark Dataframes:带条件的完全外连接