Files
docs-rust/ch15/ch15-03-drop.html
2026-06-22 21:27:36 +05:30

196 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Running Code on Cleanup with the Drop Trait</title>
</head>
<body>
<h2 id="running-code-on-cleanup-with-the-drop-trait"><a class="header" href="#running-code-on-cleanup-with-the-drop-trait">Running Code on Cleanup with the <code>Drop</code> Trait</a></h2>
<p>The second trait important to the smart pointer pattern is <code>Drop</code>, which lets
you customize what happens when a value is about to go out of scope. You can
provide an implementation for the <code>Drop</code> trait on any type, and that code can
be used to release resources like files or network connections.</p>
<p>Were introducing <code>Drop</code> in the context of smart pointers because the
functionality of the <code>Drop</code> trait is almost always used when implementing a
smart pointer. For example, when a <code>Box&lt;T&gt;</code> is dropped, it will deallocate the
space on the heap that the box points to.</p>
<p>In some languages, for some types, the programmer must call code to free memory
or resources every time they finish using an instance of those types. Examples
include file handles, sockets, and locks. If the programmer forgets, the system
might become overloaded and crash. In Rust, you can specify that a particular
bit of code be run whenever a value goes out of scope, and the compiler will
insert this code automatically. As a result, you dont need to be careful about
placing cleanup code everywhere in a program that an instance of a particular
type is finished with—you still wont leak resources!</p>
<p>You specify the code to run when a value goes out of scope by implementing the
<code>Drop</code> trait. The <code>Drop</code> trait requires you to implement one method named
<code>drop</code> that takes a mutable reference to <code>self</code>. To see when Rust calls <code>drop</code>,
lets implement <code>drop</code> with <code>println!</code> statements for now.</p>
<p>Listing 15-14 shows a <code>CustomSmartPointer</code> struct whose only custom
functionality is that it will print <code>Dropping CustomSmartPointer!</code> when the
instance goes out of scope, to show when Rust runs the <code>drop</code> method.</p>
<figure class="listing" id="listing-15-14">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&amp;mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created");
}</code></pre>
<figcaption><a href="#listing-15-14">Listing 15-14</a>: A <code>CustomSmartPointer</code> struct that implements the <code>Drop</code> trait where we would put our cleanup code</figcaption>
</figure>
<p>The <code>Drop</code> trait is included in the prelude, so we dont need to bring it into
scope. We implement the <code>Drop</code> trait on <code>CustomSmartPointer</code> and provide an
implementation for the <code>drop</code> method that calls <code>println!</code>. The body of the
<code>drop</code> method is where you would place any logic that you wanted to run when an
instance of your type goes out of scope. Were printing some text here to
demonstrate visually when Rust will call <code>drop</code>.</p>
<p>In <code>main</code>, we create two instances of <code>CustomSmartPointer</code> and then print
<code>CustomSmartPointers created</code>. At the end of <code>main</code>, our instances of
<code>CustomSmartPointer</code> will go out of scope, and Rust will call the code we put
in the <code>drop</code> method, printing our final message. Note that we didnt need to
call the <code>drop</code> method explicitly.</p>
<p>When we run this program, well see the following output:</p>
<pre><code class="language-console">$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/drop-example`
CustomSmartPointers created
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
</code></pre>
<p>Rust automatically called <code>drop</code> for us when our instances went out of scope,
calling the code we specified. Variables are dropped in the reverse order of
their creation, so <code>d</code> was dropped before <code>c</code>. This examples purpose is to
give you a visual guide to how the <code>drop</code> method works; usually you would
specify the cleanup code that your type needs to run rather than a print
message.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="dropping-a-value-early-with-std-mem-drop"></a></p>
<p>Unfortunately, its not straightforward to disable the automatic <code>drop</code>
functionality. Disabling <code>drop</code> isnt usually necessary; the whole point of the
<code>Drop</code> trait is that its taken care of automatically. Occasionally, however,
you might want to clean up a value early. One example is when using smart
pointers that manage locks: You might want to force the <code>drop</code> method that
releases the lock so that other code in the same scope can acquire the lock.
Rust doesnt let you call the <code>Drop</code> traits <code>drop</code> method manually; instead,
you have to call the <code>std::mem::drop</code> function provided by the standard library
if you want to force a value to be dropped before the end of its scope.</p>
<p>Trying to call the <code>Drop</code> traits <code>drop</code> method manually by modifying the
<code>main</code> function from Listing 15-14 wont work, as shown in Listing 15-15.</p>
<figure class="listing" id="listing-15-15">
<span class="file-name">Filename: src/main.rs</span>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">struct CustomSmartPointer {
</span><span class="boring"> data: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Drop for CustomSmartPointer {
</span><span class="boring"> fn drop(&amp;mut self) {
</span><span class="boring"> println!("Dropping CustomSmartPointer with data `{}`!", self.data);
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created");
c.drop();
println!("CustomSmartPointer dropped before the end of main");
}</code></pre>
<figcaption><a href="#listing-15-15">Listing 15-15</a>: Attempting to call the <code>drop</code> method from the <code>Drop</code> trait manually to clean up early</figcaption>
</figure>
<p>When we try to compile this code, well get this error:</p>
<pre><code class="language-console">$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
--&gt; src/main.rs:16:7
|
16 | c.drop();
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
16 - c.drop();
16 + drop(c);
|
For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` (bin "drop-example") due to 1 previous error
</code></pre>
<p>This error message states that were not allowed to explicitly call <code>drop</code>. The
error message uses the term <em>destructor</em>, which is the general programming term
for a function that cleans up an instance. A <em>destructor</em> is analogous to a
<em>constructor</em>, which creates an instance. The <code>drop</code> function in Rust is one
particular destructor.</p>
<p>Rust doesnt let us call <code>drop</code> explicitly, because Rust would still
automatically call <code>drop</code> on the value at the end of <code>main</code>. This would cause a
double free error because Rust would be trying to clean up the same value twice.</p>
<p>We cant disable the automatic insertion of <code>drop</code> when a value goes out of
scope, and we cant call the <code>drop</code> method explicitly. So, if we need to force
a value to be cleaned up early, we use the <code>std::mem::drop</code> function.</p>
<p>The <code>std::mem::drop</code> function is different from the <code>drop</code> method in the <code>Drop</code>
trait. We call it by passing as an argument the value we want to force-drop.
The function is in the prelude, so we can modify <code>main</code> in Listing 15-15 to
call the <code>drop</code> function, as shown in Listing 15-16.</p>
<figure class="listing" id="listing-15-16">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024"><span class="boring">struct CustomSmartPointer {
</span><span class="boring"> data: String,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl Drop for CustomSmartPointer {
</span><span class="boring"> fn drop(&amp;mut self) {
</span><span class="boring"> println!("Dropping CustomSmartPointer with data `{}`!", self.data);
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created");
drop(c);
println!("CustomSmartPointer dropped before the end of main");
}</code></pre>
<figcaption><a href="#listing-15-16">Listing 15-16</a>: Calling <code>std::mem::drop</code> to explicitly drop a value before it goes out of scope</figcaption>
</figure>
<p>Running this code will print the following:</p>
<pre><code class="language-console">$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/drop-example`
CustomSmartPointer created
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main
</code></pre>
<p>The text <code>Dropping CustomSmartPointer with data `some data`!</code> is printed
between the <code>CustomSmartPointer created</code> and <code>CustomSmartPointer dropped before the end of main</code> text, showing that the <code>drop</code> method code is called to drop
<code>c</code> at that point.</p>
<p>You can use code specified in a <code>Drop</code> trait implementation in many ways to
make cleanup convenient and safe: For instance, you could use it to create your
own memory allocator! With the <code>Drop</code> trait and Rusts ownership system, you
dont have to remember to clean up, because Rust does it automatically.</p>
<p>You also dont have to worry about problems resulting from accidentally
cleaning up values still in use: The ownership system that makes sure
references are always valid also ensures that <code>drop</code> gets called only once when
the value is no longer being used.</p>
<p>Now that weve examined <code>Box&lt;T&gt;</code> and some of the characteristics of smart
pointers, lets look at a few other smart pointers defined in the standard
library.</p>
</body>
</html>