DEV Community

Cover image for [Rust Guide] 15.4 Drop Trait - Goodbye to Manual Cleanup, Release is Safe
SomeB1oody
SomeB1oody

Posted on • Edited on • Originally published at someb1oody.github.io

[Rust Guide] 15.4 Drop Trait - Goodbye to Manual Cleanup, Release is Safe

15.4.1 The Meaning of the Drop Trait

If a type implements the Drop trait, it can let the programmer customize what happens when a value goes out of scope. For example, releasing files or network resources.

In some languages, such as C/C++, programmers must write code to free memory or resources every time they finish using an instance of certain types. If they forget, the system may become overloaded and crash. In Rust, programmers can specify code to run whenever a value goes out of scope, and the compiler automatically inserts that code.

Any type can implement the Drop trait, and Drop only requires implementing the drop method, whose parameter is a mutable reference to self. Drop is in the prelude, so you do not need to import it manually. Take a look at an example:

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}
Enter fullscreen mode Exit fullscreen mode
  • The CustomSmartPointer struct has a data field of type String.
  • impl Drop for CustomSmartPointer implements the Drop trait for CustomSmartPointer. Inside it, we implement the drop method, whose parameter is &mut self. This method is usually used to release resources, but for demonstration purposes, it only prints a line and outputs the data field from self.
  • In main, two instances of CustomSmartPointer are created: c stores "my stuff" and d stores "other stuff". Finally, it prints "CustomSmartPointers created.".

Output:

CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
Enter fullscreen mode Exit fullscreen mode

The program first prints the content of println! in main, which is "CustomSmartPointers created.". Because c and d go out of scope at the end of main, the program then drops them in reverse order of declaration: first d, then c. Since drop in this Drop implementation prints a line, both values print a line when they are dropped.

15.4.2 Using std::mem::drop to Drop a Value Early

Unfortunately, it is hard to disable automatic drop directly, and there is no need to do so. The purpose of the Drop trait is to handle cleanup automatically.

In addition, Rust does not allow you to call the drop method of the Drop trait manually. However, you can call the standard library function std::mem::drop to drop a value early, which is equivalent to calling the drop method of Drop early. Its parameter is the value to be dropped. Take a look:

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    drop(c);
    println!("CustomSmartPointers created.");
}
Enter fullscreen mode Exit fullscreen mode

In main, we manually use drop to clean up c, while d is still dropped automatically. The output order should show c before d.

Output:

Dropping CustomSmartPointer with data `my stuff`!
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Enter fullscreen mode Exit fullscreen mode

Some people may wonder: if c is dropped before it goes out of scope, will the compiler call drop again after it goes out of scope and cause a double free error? The answer is no. Rust’s design is safe. Its ownership system ensures that references are valid, and drop is only called once when the value is determined to no longer be used.

Top comments (0)