3

Given a struct, how can a function be written so that it is automatically called at end of scope, consuming self rather than using &mut self (unlike Drop::drop)?

I would like to call other functions within that destructor that will consume each field of the struct, and I would like the destructor to be called automatically.

ljedrz
  • 20,316
  • 4
  • 69
  • 97
hpm
  • 1,202
  • 13
  • 34
  • 2
    _"consuming `self` rather than `&mut self` (unlike `Drop::drop`)"_ I'm afraid that we cannot understand what you are trying to do without a concrete example. – E_net4 Dec 14 '18 at 11:59
  • @loganfsmyth Linked to the wrong question? That’s the same one as the one I marked mine as duplicate of? – hpm Dec 15 '18 at 04:46

1 Answers1

2

This is possible with a combination of a placeholder value, mem::replace and mem::forget:

use std::mem;

struct Foo;

impl Drop for Foo {
    fn drop(&mut self) {
        let to_drop = mem::replace(self, Foo); // a placeholder with empty/default members
        to_drop.dropping_function();
    }
}

impl Foo {
    fn dropping_function(self) {
        println!("dropping Foo!");
        // call other destructors here
        mem::forget(self);
    }
}

fn main() {
    let foo = Foo;
}  // dropping Foo!

Be warned, though (citing the docs of mem::forget):

Takes ownership and "forgets" about the value without running its destructor.

Which means you need to make sure to drop everything containted in Foo yourself.

ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • It compiles and runs the function, but segfaults afterwards in my use case. So, what would you recommmend? Just leave it as an explicit destructor? – hpm Dec 14 '18 at 12:54
  • I guess the best recommendation is probably to switch the other destructors to use `&mut self`, so everything would "just work". Otherwise, some pieces of the code be helpful to suggest a different solution. – ljedrz Dec 14 '18 at 13:01
  • The struct is intended to wrap some functionality of `gfx_hal`. Each field of it is destroyed with a corresponding `gfx_hal::Backend::destroy_*` which moves and consumes the field, so I can't change it. I'm guessing the best I can do is forgo RAII and write an explicit `destroy` function that calls `gfx_hal`'s `destroy`s? – hpm Dec 14 '18 at 13:18
  • And that doesn't cause a segfault anymore? – ljedrz Dec 14 '18 at 13:23