Background:
In Rust, resource management without a garbage collector became possible due to strict ownership and object lifecycle rules. To automate resource deallocation (e.g., file descriptors, sockets, memory from external libraries), the Drop trait was introduced from the very beginning of the language's development. This is the primary way to "react" to the end of an object's life, which is used for finalization and returning resources to the operating system or freeing memory.
Problem:
Regular Rust types automatically clean up their own resources, but when a structure holds a resource that requires manual deallocation (e.g., an open file or an unsafe pointer), the developer's unwillingness or forgetfulness may lead to leaks or resource races. If Drop is implemented incorrectly (e.g., overlooking the possibility of double freeing memory), it can lead to runtime errors.
Solution:
The Drop trait allows defining a special method drop(&mut self) that is automatically called upon the destruction of a value. It is suitable for releasing resources just when the object goes out of scope. It's important to remember that resources (e.g., closing a file) should only be released here.
Example code:
struct RawFile { handle: *mut libc::FILE, } impl Drop for RawFile { fn drop(&mut self) { if !self.handle.is_null() { unsafe { libc::fclose(self.handle); } } } }
Key features:
Can you call drop explicitly for an object to release the resource earlier?
No, directly calling the drop method (&obj.drop()) is forbidden — only through the function std::mem::drop(obj), which takes ownership of the object and automatically calls drop. Calling drop() directly does not compile.
Example code:
fn main() { let f = File::open("foo.txt").unwrap(); // drop(&mut f); // Compilation error! std::mem::drop(f); // Correct: closing the file }
What happens if a structure with Drop is subjected to memcpy or move? Will the destructor be called twice?
No, the destructor is always called exactly once across the entire lifecycle of the object, and the compiler ensures this. But if unsafe copying of "raw" bytes of the structure is done or mem::forget is used, drop may not be called at all — hence, the danger.
Can you implement Drop and Copy simultaneously for the same type?
No, the compiler forbids this combination: a type implementing Drop cannot be Copy, to guarantee a single call of the destructor and eliminate the risk of double freeing a resource.
A programmer wrote a simple wrapper for working with an open file but forgot to implement Drop and close the descriptor upon object removal.
Pros:
Cons:
A developer implemented Drop for the file descriptor wrapper, explicitly closing the file in drop. Now, when any variable of this structure goes out of function scope or panic occurs, the resource is guaranteed to be released.
Pros:
Cons: