Prevent calling drop()

I have a struct like this:

struct Foo {
    b: Box<i32>,
}

impl Drop for Foo {
    fn drop(&mut self) {
        // do something
        println!("foo destroyed")
    }
}

And some day I add a function like this:

struct Bar {
    b: Box<i32>,
}


impl Foo {
    // a function to turn a foo to a bar.
    pub fn to_bar(self) -> Bar {
        Bar {
            b: self.b,
        }
    }
}

But this will not compile since Foo has implemented the trait Drop.

I tried to use ManuallyDrop, but it seems that it is designed for struct fields, I don't found a way to use it in my case.

So what can I do? Notice that not only I want to get a Bar from a Foo, but also I don't want the drop() of foo get called at all.

P.S. If I write C++, I will add a field to tell if the object is "moved", and do nothing in the destructor by checking the field. I wondered if I should do the same in Rust, or there's a better way.

Ah, yes, this is quite annoying. You can either wrap the field in an Option and use Option::take, or you can use unsafe code.

Would you kindly tell more about the unsafe code? I didn't come up with an idea with unsafe code either (except the ManuallyDrop try) :frowning:

In your particular case, you can mark the struct #[repr(transparent)], then transmute it into a Box<i32>.

This is probably what I'd do:

impl Foo {
    // a function to turn a foo to a bar.
    pub fn to_bar(self) -> Bar {
        // Safety: okay because we'll never be touching "self.b" again.
        let b = unsafe { std::ptr::read(&self.b) };

        // Note: if Foo had other fields, you would need to
        // call std::ptr::drop_in_place() for them here.

        // Forget the value so we don't call its Drop implementation
        std::mem::forget(self);

        Bar { b }
    }
}

(playground)

Assuming the Option variant isn't feasible, anyway.

4 Likes

@Michael-F-Bryan It's generally recommended to put self in ManuallyDrop and then doing the ptr::read as opposed to doing it in the other order. It is less fragile to stray panics leading to a double-free.

7 Likes

Good call! I totally forgot about the leak amplification/ppyp principle.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.