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::forget
causes 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
EventListenerHandle
should not implement theDrop
trait. -
The
EventListenerHandle
should implement theDiscard
trait instead. -
The
add_event_listener
method 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::forget
leaks all of the memory,DiscardOnDrop::leak
leaks the minimal amount of memory: unused memory is properly cleaned up. -
With
std::mem::forget
you cannot clean up a value after it has been leaked, but withDiscardOnDrop::leak
you 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§
- 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()
.
Traits§
- This trait is very similar to
Drop
: it allows for cleaning up memory and resources when they are no longer needed.