如何在删除时更改值?

时间:2015-03-22 16:27:55

标签: rust

我目前正在尝试了解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?

1 个答案:

答案 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));
}