我目前正在尝试了解 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 替换为将被正确删除的值?
最佳答案
我还不确定如何实现你的目标,但是我可以证明这一点
From my understanding, the usage of
std::ptr::write
should prevent the destructor from running
不正确:
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));
}
关于rust - 如何在下降时更改值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29196869/