We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership I: Moves, Copy, Clone, Drop step 19 of 20
Observe when destructors are skipped
pub fn leak_report(script: Vec<String>) -> Vec<String>
Implement a command interpreter that records when values are created and
destroyed. Compare ordinary destruction with mem::forget, ManuallyDrop
and an Rc reference cycle. Use the supplied logging helpers rather than
constructing the expected log directly.
Commands and output
Process commands in order and return the final log. Match the prefixes below
exactly, including their trailing space. Names are the entire remaining text:
they may be empty or contain spaces, and must not be trimmed. Matching is
case-sensitive. Only the exact string cycle invokes the cycle helper.
| Command | Action | Log entries |
|---|---|---|
normal N |
Create a tracked value, then drop it before the next command. | new N, drop N |
forget N |
Create a tracked value and pass it to std::mem::forget. |
new N |
manual N |
Create a tracked value and wrap it in std::mem::ManuallyDrop::new. |
new N |
cycle |
Call make_cycle(log.clone()). |
new cyc0, new cyc1 |
| Anything else | Record the complete command after ? . |
? <command> |
An empty script returns an empty log. For example:
Input: ["normal a", "forget b", "manual c", "normal d"]
Output: ["new a", "drop a", "new b", "new c", "new d", "drop d"]
Two of these four tracked values are destroyed: a and d. The destructors
for b and c are skipped. Bare normal is an unknown command, while
normal creates and drops a value with an empty name.
Supplied helpers
new_log() creates a shared log. tracked(name, log) returns a Tracked
value and records new <name>. Its Drop implementation records
drop <name>. Use note(log, line) to append an unknown-command entry and
snapshot(log) to return a copy of the log. Pass log.clone() to helpers
when you need to retain your own handle; this shares the log rather than
copying its entries.
make_cycle(log) creates two Rc nodes containing tracked values named
cyc0 and cyc1. Each node holds a strong reference to the other. When the
helper returns, dropping its local handles does not reduce either strong
count to zero. The cycle remains allocated and neither tracked destructor
runs. A cycle of strong references causes this behavior; an arbitrary use of
Rc, or a cycle broken with Weak, does not necessarily leak.
Destruction is useful, but not unconditional
Rust normally drops owned values when their scope ends or when they are
explicitly passed to drop. Ownership can also move elsewhere, delaying
destruction. Some safe operations deliberately prevent it:
mem::forget(value)consumes the value without running its destructor.ManuallyDrop::new(value)suppresses automatic destruction of its contents. It does not itself allocate. This exercise leaves the contents undropped; other code can safely recover them withManuallyDrop::into_inner.- A strong
Rccycle can keep values alive after external handles are gone.
Leaks can waste memory or leave resources unreleased, so they are usually
undesirable. They are not, by themselves, undefined behavior. This distinction
explains why mem::forget is safe.
It does not promise that arbitrary raw pointers remain valid after a value
is forgotten.
An unsafe abstraction must remain memory-safe when a caller forgets a value it returns. For example, a drain iterator cannot rely solely on its destructor to repair a vector containing moved-out elements. The later unsafe-code exercises examine that design; this exercise focuses on observable drop logs.
Repair the starter
The starter tries to move t.name out of a Tracked value that implements
Drop. Rust rejects that partial move with E0509. Pass the entire t to
mem::forget, and do not use it afterward. The extra forgot ... entry in
the starter is also outside the required output contract.
Keep the manual value inside its wrapper without manually dropping or
extracting it. The absence of a drop entry is intentional here. Clippy
accepting the reference does not mean leaking resources is generally good
practice, and log comparisons alone cannot prove an implementation uses the
requested ownership operations.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.