Reputation: 1429
I want to have a guard that takes a closure and runs it when it goes out of scope:
pub struct ScopeGuard<F: Fn() -> ()>(F);
impl<F: Fn() -> ()> ScopeGuard<F> {
pub fn new(f: F) -> Self { Self(f) }
}
impl<F: Fn() -> ()> Drop for ScopeGuard<F> {
fn drop(&mut self) { self.0(); }
}
Can I be sure that it will always be dropped not earlier than at the end of the scope, if the variable it is assigned to is unused? Or may Rust decide to optimize and drop it earlier? In other words, would the following snippet always print "Scope ended" before "Guard dropped", no matter the compiler flags, version, etc?
{
let _guard = ScopeGuard::new(|| println!("Guard dropped"));
// ... some other code that doesn't use _guard
println!("Scope ended");
}
Also, just in case I missed, is there something like my ScopeGuard
already in standard library?
Upvotes: 1
Views: 860
Reputation: 71300
Compiler optimizations are not allowed to change observable behavior. If you can observe the fact that an optimization was applied, in other words, if there is difference in behavior between when the optimization is applied and when not, the optimization is invalid. This is commonly referred to as the as-if rule.
(What constitutes "behavior" is not trivial, for example timing is not considered part of that - otherwise any optimization that makes the program run faster wouldn't be allowed, but this is not relevant here).
So yes, you can be sure the guard will always be dropped at the end of the scope. Whether this is what will actually happen may not be the case - but this will always be what you will see. So "Scope ended" will always be printed before "Guard dropped".
Upvotes: 4