Expand description
There are situations where you need to intentionally leak some memory but not other memory. This crate can help!
But before I explain, you are probably wondering: why would I want to leak memory in the first place?
There are certain rare situations where leaking memory is either desirable or necessary.
As an example, let’s say I am using stdweb, which lets me use JavaScript APIs in Rust.
So I write some code like this:
node.add_event_listener(|event: ClickEvent| {
// ...
});Seems reasonable, right? But there’s a problem: the add_event_listener method
returns an EventListenerHandle, and when the EventListenerHandle is dropped it
will remove the event listener.
Because I’m not using the EventListenerHandle, it is immediately dropped, so it
receives no events!
Okay, no problem, just use std::mem::forget:
// This will automatically remove the event listener when `handle` is dropped
let handle = node.add_event_listener(|event: ClickEvent| {
// ...
});
// Now it will no longer remove the event listener
std::mem::forget(handle);Now the event listener will remain alive forever, which is what I want.
But there’s two problems with this:
-
I want it to keep the event listener alive forever, but I also want it to clean up any unused internal memory. Using
std::mem::forgetcauses it to leak all of the memory, which is wasteful. -
There are situations where I want to leak the event listener, and then later unleak it. That’s not possible with
std::mem::forget.
The solution to all of these problems is:
-
The
EventListenerHandleshould not implement theDroptrait. -
The
EventListenerHandleshould implement theDiscardtrait instead. -
The
add_event_listenermethod should returnDiscardOnDrop<EventListenerHandle>.
Now let’s look at what is possible:
// This will automatically remove the event listener when `handle` is dropped
let handle = node.add_event_listener(|event: ClickEvent| {
// ...
});
// Now it will no longer remove the event listener, this is similar to `std::mem::forget`
let leaked = DiscardOnDrop::leak(handle);
// Now it will remove the event listener, even though it was leaked
leaked.discard();There’s two huge differences between DiscardOnDrop::leak
and std::mem::forget:
-
std::mem::forgetleaks all of the memory,DiscardOnDrop::leakleaks the minimal amount of memory: unused memory is properly cleaned up. -
With
std::mem::forgetyou cannot clean up a value after it has been leaked, but withDiscardOnDrop::leakyou can manually discard the value even after it has been leaked.
Most of the time you don’t need to worry about any of this:
DiscardOnDrop will automatically call
discard when it is dropped, so in that situation
Discard behaves the same as Drop.
So you can use normal Rust idioms, and everything works as you would expect. You only need to
worry about Discard when you need to intentionally leak some memory.
Structs§
- Discard
OnDrop - If you have a value which implements
Discard, you can useDiscardOnDrop::new(value)which will wrap the value. When the wrapper is dropped it will automatically callvalue.discard().