我正在阅读"learn rust with entirely too many linked lists" 。 在第 2.7 章中,作者说“我们不能在释放后删除 Box 的内容”。一个值被删除后如何被释放?释放不会在 drop 的实现中发生吗?或者这些是不同的概念?
在某些情况下,作者正在解释为什么链表的特定实现不是尾递归的,因此无法被编译器优化。
链接列表:
pub struct List {
head: Link,
}
enum Link {
Empty,
More(Box<Node>),
}
struct Node {
elem: i32,
next: Link,
}
删除实现:
impl Drop for List {
fn drop(&mut self) {
// NOTE: you can't actually explicitly call `drop` in real Rust code;
// we're pretending to be the compiler!
self.head.drop(); // tail recursive - good!
}
}
impl Drop for Link {
fn drop(&mut self) {
match *self {
Link::Empty => {} // Done!
Link::More(ref mut boxed_node) => {
boxed_node.drop(); // tail recursive - good!
}
}
}
}
impl Drop for Box<Node> {
fn drop(&mut self) {
self.ptr.drop(); // uh oh, not tail recursive!
deallocate(self.ptr);
}
}
impl Drop for Node {
fn drop(&mut self) {
self.next.drop();
}
}
最佳答案
Wouldn't the deallocation occur in the implementation of drop or are these separate concepts?
它们是不同的概念。在示例代码中,Drop
表示“清理我的内容/拥有的资源”,deallocate
意思是“将我实际存储的内存返回到池中”。
drop
方法是通过引用现有实例来运行的。 The definition of drop
actually says :
When this method has been called,
self
has not yet been deallocated. That only happens after the method is over. If this wasn’t the case,self
would be a dangling reference.
因此,head
必须完全删除才能释放它。并且删除过程需要先删除列表中的所有节点,每个节点只有在删除完成后才会释放关联的节点,从而导致堆栈为 drop
s,其中每个将后跟 deallocate
,但毕竟是 drop
和 deallocates
在它们上面的堆栈上完成。因为您无法执行单个 deallocate
直到drop
已经在整个堆栈中被调用(此时尾节点的drop
返回并且尾节点是第一个释放的),它不能以尾递归方式实现。
旁注:这与您在 C++ 中尝试使用 std::shared_ptr
实现链表时看到的问题完全相同。或std::unique_ptr
对于next
指针。就像 Rust 一样,C++ 将销毁(清理对象内的资源)与释放(释放对象所占用的内存)区分开来。当 head
unique_ptr
被清除后,在它释放内存之前,它必须告诉“head
+ 1”来清除它自己的 unique_ptr
,这又告诉“head
+ 2”清除其unique_ptr
等等。在每种情况下,销毁(通过析构函数)必须先于释放(对于堆分配的内容可能通过 operator delete
发生,或者只是由编译器收缩堆栈而不实际为堆栈分配的内容释放任何内存)。
关于rust - 变量被删除后如何释放?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72204310/