我目前正在尝试了解drop
的工作原理。以下代码崩溃,我不明白为什么。根据我的理解,std::ptr::write
的使用应该防止析构函数(编辑:原始值,这里:Rc)运行(在这种情况下,内存泄漏旁边不应该发生任何坏事)。但它似乎不是那样做的(playpen,用-O0编译)
use std::rc::Rc;
use std::mem;
use std::ptr;
enum Foo {
Bar(Rc<usize>),
Baz
}
use Foo::*;
impl Drop for Foo {
fn drop(&mut self) {
match *self {
Bar(_) => {
unsafe { ptr::write(self, Foo::Baz) }
//unsafe { mem::forget(mem::replace(self, Foo::Baz)) }
}
Baz => ()
}
}
}
fn main() {
let _ = Foo::Bar(Rc::new(23));
}
发出溢出错误:
thread '<main>' panicked at 'arithmetic operation overflowed', /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/liballoc/rc.rs:755
另一个变体退出非法指令。为什么会这样?如何用一个可以正确删除的值替换self?
答案 0 :(得分:1)
我不确定如何实现目标,但我可以证明
根据我的理解,
std::ptr::write
的使用应该阻止析构函数运行
不是真的:
use std::mem;
use std::ptr;
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) { println!("Dropping!") }
}
enum Foo {
Bar(Noisy),
Baz
}
use Foo::*;
impl Drop for Foo {
fn drop(&mut self) {
println!("1");
match self {
&mut Bar(_) => {
println!("2");
unsafe { ptr::write(self, Foo::Baz) }
println!("3");
}
&mut Baz => {
println!("4");
}
}
println!("5");
}
}
fn main() {
let _ = Foo::Bar(Noisy);
}
打印:
1
2
3
5
Dropping!
表示Foo::Bar
的析构函数仍在运行,包括Noisy
的析构函数。
可能的解决方案是使用Option::take
:
use std::mem;
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) { println!("Dropping!") }
}
enum Foo {
Bar(Option<Noisy>),
Baz
}
impl Drop for Foo {
fn drop(&mut self) {
match *self {
Foo::Bar(ref mut x) => {
unsafe { mem::forget(x.take()) }
}
Foo::Baz => {}
}
}
}
fn main() {
let _ = Foo::Bar(Some(Noisy));
}