|
| 1 | +# Destructors |
| 2 | + |
| 3 | +When an [intialized] [variable] in Rust goes out of scope or a [temporary] is |
| 4 | +no longer needed its _destructor_ is run. [Assignment] also runs the destructor |
| 5 | +of its left-hand operand, unless it's an unitialized variable. If a [struct] |
| 6 | +variable has been partially initialized, only its initialized fields are |
| 7 | +dropped. |
| 8 | + |
| 9 | +The destrutor of a type consists of |
| 10 | + |
| 11 | +1. Calling its [`std::ops::Drop::drop`] method, if it has one. |
| 12 | +2. Recursively running the destructor of all of its fields. |
| 13 | + * The fields of a [struct], [tuple] or [enum variant] are dropped in |
| 14 | + declaration order. \* |
| 15 | + * The elements of an [array] or (owned) [slice][array] are dropped from the |
| 16 | + first element to the last. \* |
| 17 | + * The captured values of a [closure] are dropped in an unspecified order. |
| 18 | + * [Trait objects] run the destructor of the underlying type. |
| 19 | + * Other types don't result in any further drops. |
| 20 | + |
| 21 | +\* This order was stabilized in [RFC 1857]. |
| 22 | + |
| 23 | +Variables are dropped in reverse order of declaration. Variables declared in |
| 24 | +the same pattern drop in an unspecified ordered. |
| 25 | + |
| 26 | +If a destructor must be run manually, such as when implementing your own smart |
| 27 | +pointer, [`std::ptr::drop_in_place`] can be used. |
| 28 | + |
| 29 | +Some examples: |
| 30 | + |
| 31 | +```rust |
| 32 | +struct ShowOnDrop(&'static str); |
| 33 | + |
| 34 | +impl Drop for ShowOnDrop { |
| 35 | + fn drop(&mut self) { |
| 36 | + println!("{}", self.0); |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +{ |
| 41 | + let mut overwritten = ShowOnDrop("Drops when overwritten"); |
| 42 | + overwritten = ShowOnDrop("drops when scope ends"); |
| 43 | +} |
| 44 | +# println!(""); |
| 45 | +{ |
| 46 | + let declared_first = ShowOnDrop("Dropped last"); |
| 47 | + let declared_last = ShowOnDrop("Dropped first"); |
| 48 | +} |
| 49 | +# println!(""); |
| 50 | +{ |
| 51 | + // Tuple elements drop in forwards order |
| 52 | + let tuple = (ShowOnDrop("Tuple first"), ShowOnDrop("Tuple second")); |
| 53 | +} |
| 54 | +# println!(""); |
| 55 | +loop { |
| 56 | + // Tuple expression doesn't finish evaluating so temporaries drop in reverse order: |
| 57 | + let partial_tuple = (ShowOnDrop("Temp first"), ShowOnDrop("Temp second"), break); |
| 58 | +} |
| 59 | +# println!(""); |
| 60 | +{ |
| 61 | + let moved; |
| 62 | + // No destructor run on assignment. |
| 63 | + moved = ShowOnDrop("Drops when moved"); |
| 64 | + // drops now, but is then uninitialized |
| 65 | + moved; |
| 66 | + let uninitialized: ShowOnDrop; |
| 67 | + // Only first element drops |
| 68 | + let mut partially_initialized: (ShowOnDrop, ShowOnDrop); |
| 69 | + partially_initialized.0 = ShowOnDrop("Partial tuple first"); |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +## Not running destructors |
| 74 | + |
| 75 | +Not running destructors in Rust is safe, so `unsafe` code cannot assume a |
| 76 | +variable will be dropped, even if it has a type that isn't `'static`. |
| 77 | +[`std::mem::forget`] can be used to avoid running the destructor of a local |
| 78 | +variable. [`std::mem::ManuallyDrop`] provides a wrapper to prevent a field |
| 79 | +automatically being dropped recursively. |
| 80 | + |
| 81 | +[initialized]: glossary.html#initialized |
| 82 | +[variable]: variables.html |
| 83 | +[temporary]: expressions.html#temporary-lifetimes |
| 84 | +[Assignment]: expressions/operator-expr.html#assignment-expressions |
| 85 | +[`std::ops::Drop::drop`]: ../std/ops/trait.Drop.html |
| 86 | +[RFC 1857]: https://github.com/rust-lang/rfcs/blob/master/text/1857-stabilize-drop-order.md |
| 87 | +[struct]: types.html#struct |
| 88 | +[tuple]: types.html#tuple-types |
| 89 | +[enum variant]: types.html#enumeration-types |
| 90 | +[array]: types.html#array-and-slice-types |
| 91 | +[closure]: types.html#closure-types |
| 92 | +[Trait objects]: types.html#trait-objects |
| 93 | +[`std::ptr::drop_in_place`]: ../std/ptr/fn.drop_in_place.html |
| 94 | +[`std::mem::forget`]: ../std/mem/fn.forget.html |
| 95 | +[`std::mem::ManuallyDrop`]: ../std/mem/union.ManuallyDrop.html |
0 commit comments