Theme
Q025. When exactly is a value dropped?
Short Answer
An initialized value is normally dropped when control leaves its drop scope, whether by reaching the end, returning, breaking, using ?, or unwinding a panic. Reassignment drops the previous initialized value, and std::mem::drop can end ownership earlier. Moved-out or uninitialized places are not dropped, and aborting or deliberately leaking can skip destruction.
Deep Dive
Every local and temporary is associated with a drop scope. Leaving nested scopes drops inner values before outer values. Function parameters live in the function-body scope, while temporary scopes can be shorter and depend on expression syntax and Rust edition rules.
Other important drop points are:
- assigning over an initialized place drops its old value;
std::mem::drop(value)moves the value into a function where it is immediately destroyed;- early
return,break, and?destroy initialized values in scopes being exited; - panic unwinding runs cleanup, but
panic = "abort"does not.
Non-lexical lifetimes can end a borrow after its last use, but they do not generally move an owned local's semantic drop point to its last use.
Internal Model
The compiler calculates drop scopes and inserts MIR drop terminators on each relevant control-flow edge. Drop elaboration removes drops for places known to be uninitialized and makes uncertain drops conditional.
Physical storage can be reused earlier when that change is unobservable, but custom destructor behavior must occur at the language-defined drop point.
Example
rust
struct Trace(&'static str);
impl Drop for Trace {
fn drop(&mut self) {
println!("drop {}", self.0);
}
}
fn main() {
let _outer = Trace("outer");
{
let inner = Trace("inner");
drop(inner);
println!("inner released");
}
println!("leaving main");
}Common Mistakes
- Saying every local is dropped immediately after its last use.
- Assuming panic always runs destructors regardless of panic strategy.
- Expecting a moved-from source place to be dropped at scope exit.
Follow-ups
- How are temporary drop scopes determined?
- What is the difference between panic unwinding and aborting?
- Why can conditional moves require runtime drop flags?
Related
- Q010. How does ownership determine a value's lifetime?
- Q017. How does ownership flow through branches, loops, and conditional initialization?
- Q029. What are drop flags and why does the compiler need them?
References
- Rust Reference
- Rust Standard Library
- rustc-dev-guide