How to force drop order of struct fields

Is there any way to efficiently force Drop order of struct fields? or a workaround?

I know that Drop order is currently undefined in Rust (https://github.com/rust-lang/rfcs/issues/744), but I need to make sure that fields get dropped in certain order, because I'm using a C library that will not get cleaned up properly otherwise.

example:

struct Foo {
    a:A,
    b:B,
    c:C,
}

I want to make sure fields get dropped in order C,B,A.
Not A,B,C, like how Rust seems to do (most of the time), which will break cleanup functions for B and C.

The only safe solution I have found so far is to wrap all fields in Option and then call x.take()'s in Drop to force the drop order, but that is pretty silly.

I'm only guessing, but I'm assuming it is because C requires B and A, and B requires A (simplified)? If so, you might be able to wrap it in types for different states of construction/destruction:

struct StateA { a: A }
struct StateB { b: B, state_a: StateA }
struct StateC { c: C, state_b: StateB }

struct Foo { state_c: StateC }

There might be better names for your situation. And of course, it might turn out to be more sillier for your case than the Option<T> variant. Plus it's monday and I might be missing something.

yes

I'm bit doubtful this works.
Since the drop order is undefined, StateB for example could drop state_a before b.
This would mean that a gets dropped before b. Right?

Yeah, I think you're right. Sorry about the noise, like I said "monday" :slight_smile:

Do you really need A, B and C to be Drop by themselves? If they depend on each other maybe it's better to implement Drop only for containing struct?

Let me elaborate.

I'm using rust-sdl2 (https://github.com/AngryLawyer/rust-sdl2).
I want to store different SDL handles on a single struct so that i don't have to pass multiple context parameters to functions that need access to them.

Code looks like this

pub struct Context {
    pub sdl: sdl2::Sdl,
    pub video: sdl2::VideoSubsystem, // depends on sdl
    pub renderer: sdl2::render::Renderer<'static>, // depends on video
    pub event_pump: sdl2::EventPump, // depends on sdl
    .. // other handles for sdl_mixer etc.
}

impl Context {
    pub fn new() -> Result<Context, String> {
        ..
        let sdl = sdl2::init().unwrap();
        let video = sdl.video().unwrap();
        ..
        let mut renderer = window.renderer().build().unwrap();
        ..
        Ok(Context{ sdl:sdl, video:video, renderer:renderer })
    }
}

Now, I suppose I could store borrow references in the struct as well, but then the user would have to initialize SDL and pass the references himself.

As the poster above you said: implement Drop manually on the struct and call the drop method on the fields in dependency order.

If I try to call drop() manually I get error: error: explicit use of destructor method [E0040]

Don't call it manually. It will be called after variable goes out of scope
or use

which has very interesting implementation, just look at its source

Unfortunatelly std::mem::drop won't help here, because you can't drop fields of a mutable reference.

@fzzy you can store references in the Context and still avoid

the user would have to initialize SDL and pass the references himself.

If you use a closure based API

fn withContext<F>(
    callback: F // user creates the callback
)
    where F: FnOnce(&mut Context) 
{
    let sdl = ...;
    let video = ...;
    let ctx = Context { video: &mut video, sdl: &mut sdl, ...};
    callback(&mut ctx);
}

Alternatively, you can use a by-value Context and require the user to call a special cleanup function:

fn cleanump(ctxByValue: Context) {
    let Context {sdl, video, ...} = ctxByValue;
    drop(video);
    drop(sdl);
}
2 Likes

[quote="fzzy, post:1, topic:6203"]
I need to make sure that fields get dropped in certain order, because I'm using a C library that will not get cleaned up properly otherwise.
[/quote]Are you certain of this? This would be a bug in the bindings. After looking at rust-sdl2 sources it seems they go to lengths to make sure cleanup is performed in correct order.

2 Likes

Oh, it's like that.
Nevermind then I'm a dummie.