Search code examples
rustraii

Does a user-defined drop for a struct also drop its fields implicitly in Rust?


Let's say I have a struct

struct Foo {
    a: Box<usize>,
    b: Box<usize>,
}

And I'd like to do something with a and b when dropping a Foo instance like this

impl Drop for Foo {
    fn drop(&mut self) {
        println!("{}", self.a + self.b);
    }
}

Will Box a and b get dropped after this drop? Does my drop implementation overwrites the default impl for drop? Like what's the actual workflow here?

Moreover, if I manually call something like foo.drop(), this only does what I implemented but not actually dropping two boxes. How do I make sure they are dropped?


Solution

  • Will Box a and b get dropped after this drop? Does my drop implementation overwrites the default impl for drop?

    Rust's drop glue will ensure that the fields of Foo are dropped in the order they are declared, after your custom drop implementation. So, in this case, when a Foo gets dropped:

    • <Foo as Drop>::drop() is invoked on the Foo.
    • The Foo's a is dropped.
    • The Foo's b is dropped.

    We can prove this to ourselves with the following program:

    #![allow(unused)]
    
    struct Foo {
        a: Bar,
        b: Bar,
    }
    
    impl Foo {
        pub fn new() -> Self {
            Self {
                a: Bar("a"),
                b: Bar("b"),
            }
        }
    }
    
    impl Drop for Foo {
        fn drop(&mut self) {
            println!("Foo dropped");
        }
    }
    
    struct Bar(&'static str);
    
    impl Drop for Bar {
        fn drop(&mut self) {
            println!("Bar named \"{}\" dropped", self.0);
        }
    }
    
    fn main() {
        Foo::new();
    }
    

    The output of this program is:

    Foo dropped
    Bar named "a" dropped
    Bar named "b" dropped
    

    (Playground)

    Moreover, if I manually call something like foo.drop(), this only does what I implemented but not actually dropping two boxes.

    You can't manually call Drop::drop(). This is a special case in the Rust language. If you attempt to call foo.drop() the compiler will reject your program:

    error[E0040]: explicit use of destructor method