How to change the value when dropping?

I am currently trying to understand how it works drop. The following code fails, and I do not understand why. In my opinion, use std::ptr::writeshould prevent the destructor from starting (edit: original value here: Rc) (in this case, nothing should happen next to a memory leak). But it doesn't seem to be that way ( playpen , compile with -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));
}

gives an overflow error:

thread '<main>' panicked at 'arithmetic operation overflowed', /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/liballoc/rc.rs:755

Another option terminates with illegal instruction. Why is this happening? How can I replace self with a value that will be correctly omitted?

0
source share
1 answer

I’m not yet sure how to accomplish your goal, but I can show that

, 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));
}
+1

All Articles