The Drop Trait

Values which implement Drop can specify code to run when they go out of scope:

  1. struct Droppable {
  2.     name: &'static str,
  3. }
  4. impl Drop for Droppable {
  5.     fn drop(&mut self) {
  6.         println!("Dropping {}", self.name);
  7.     }
  8. }
  9. fn main() {
  10.     let a = Droppable { name: "a" };
  11.     {
  12.         let b = Droppable { name: "b" };
  13.         {
  14.             let c = Droppable { name: "c" };
  15.             let d = Droppable { name: "d" };
  16.             println!("Exiting block B");
  17.         }
  18.         println!("Exiting block A");
  19.     }
  20.     drop(a);
  21.     println!("Exiting main");
  22. }

This slide should take about 8 minutes.

  • Note that std::mem::drop is not the same as std::ops::Drop::drop.
  • Values are automatically dropped when they go out of scope.
  • When a value is dropped, if it implements std::ops::Drop then its Drop::drop implementation will be called.
  • All its fields will then be dropped too, whether or not it implements Drop.
  • std::mem::drop is just an empty function that takes any value. The significance is that it takes ownership of the value, so at the end of its scope it gets dropped. This makes it a convenient way to explicitly drop values earlier than they would otherwise go out of scope.
    • This can be useful for objects that do some work on drop: releasing locks, closing files, etc.

Discussion points:

  • Why doesn’t Drop::drop take self?
    • Short-answer: If it did, std::mem::drop would be called at the end of the block, resulting in another call to Drop::drop, and a stack overflow!
  • Try replacing drop(a) with a.drop().