]> git.proxmox.com Git - rustc.git/blob - src/doc/book/second-edition/src/ch15-03-drop.md
da3e193fa10b7692e6c190982fa69135ec12b0c6
[rustc.git] / src / doc / book / second-edition / src / ch15-03-drop.md
1 ## The `Drop` Trait Runs Code on Cleanup
2
3 The second trait important to the smart pointer pattern is `Drop`, which lets
4 us customize what happens when a value is about to go out of scope. We can
5 provide an implementation for the `Drop` trait on any type, and the code we
6 specify can be used to release resources like files or network connections.
7 We’re introducing `Drop` in the context of smart pointers because the
8 functionality of the `Drop` trait is almost always used when implementing a
9 smart pointer. For example, `Box<T>` customizes `Drop` to deallocate the space
10 on the heap that the box points to.
11
12 In some languages, the programmer must call code to free memory or resources
13 every time they finish using an instance of a smart pointer. If they forget,
14 the system might become overloaded and crash. In Rust, we can specify that a
15 particular bit of code should be run whenever a value goes out of scope, and
16 the compiler will insert this code automatically. As a result, we don’t need to
17 be careful about placing cleanup code everywhere in a program that an instance
18 of a particular type is finished with, but we still won’t leak resources!
19
20 We specify the code to run when a value goes out of scope by implementing the
21 `Drop` trait. The `Drop` trait requires us to implement one method named `drop`
22 that takes a mutable reference to `self`. To see when Rust calls `drop`, let’s
23 implement `drop` with `println!` statements for now.
24
25 Listing 15-14 shows a `CustomSmartPointer` struct whose only custom
26 functionality is that it will print `Dropping CustomSmartPointer!` when the
27 instance goes out of scope. This example demonstrates when Rust runs the `drop`
28 function:
29
30 <span class="filename">Filename: src/main.rs</span>
31
32 ```rust
33 struct CustomSmartPointer {
34 data: String,
35 }
36
37 impl Drop for CustomSmartPointer {
38 fn drop(&mut self) {
39 println!("Dropping CustomSmartPointer with data `{}`!", self.data);
40 }
41 }
42
43 fn main() {
44 let c = CustomSmartPointer { data: String::from("my stuff") };
45 let d = CustomSmartPointer { data: String::from("other stuff") };
46 println!("CustomSmartPointers created.");
47 }
48 ```
49
50 <span class="caption">Listing 15-14: A `CustomSmartPointer` struct that
51 implements the `Drop` trait where we would put our cleanup code</span>
52
53 The `Drop` trait is included in the prelude, so we don’t need to import it. We
54 implement the `Drop` trait on `CustomSmartPointer` and provide an
55 implementation for the `drop` method that calls `println!`. The body of the
56 `drop` function is where you would place any logic that you wanted to run when
57 an instance of your type goes out of scope. We’re printing some text here to
58 demonstrate when Rust will call `drop`.
59
60 In `main`, we create two instances of `CustomSmartPointer` and then print
61 `CustomSmartPointers created.`. At the end of `main`, our instance of
62 `CustomSmartPointer` will go out of scope, and Rust will call the code we put
63 in the `drop` method, printing our final message. Note that we didn’t need to
64 call the `drop` method explicitly.
65
66 When we run this program, we’ll see the following output:
67
68 ```text
69 CustomSmartPointers created.
70 Dropping CustomSmartPointer with data `other stuff`!
71 Dropping CustomSmartPointer with data `my stuff`!
72 ```
73
74 Rust automatically called `drop` for us when our instance went out of scope,
75 calling the code we specified. Variables are dropped in the reverse order of
76 the order in which they were created, so `d` was dropped before `c`. This
77 example just gives you a visual guide to how the `drop` method works, but
78 usually you would specify the cleanup code that your type needs to run rather
79 than a print message.
80
81 ### Dropping a Value Early with `std::mem::drop`
82
83 Unfortunately, it’s not straightforward to disable the automatic `drop`
84 functionality. Disabling `drop` isn’t usually necessary; the whole point of the
85 `Drop` trait is that it’s taken care of automatically. Occasionally, you might
86 want to clean up a value early. One example is when using smart pointers that
87 manage locks: you might want to force the `drop` method that releases the lock
88 to run so other code in the same scope can acquire the lock. Rust doesn’t let
89 us call the `Drop` trait’s `drop` method manually; instead we have to call the
90 `std::mem::drop` function provided by the standard library if we want to force
91 a value to be dropped before the end of its scope.
92
93 Let’s see what happens when we try to call the `Drop` trait’s `drop` method
94 manually by modifying the `main` function in Listing 15-14, as shown in Listing
95 15-15:
96
97 <span class="filename">Filename: src/main.rs</span>
98
99 ```rust,ignore
100 fn main() {
101 let c = CustomSmartPointer { data: String::from("some data") };
102 println!("CustomSmartPointer created.");
103 c.drop();
104 println!("CustomSmartPointer dropped before the end of main.");
105 }
106 ```
107
108 <span class="caption">Listing 15-15: Attempting to call the `drop` method from
109 the `Drop` trait manually to clean up early</span>
110
111 When we try to compile this code, we’ll get this error:
112
113 ```text
114 error[E0040]: explicit use of destructor method
115 --> src/main.rs:14:7
116 |
117 14 | c.drop();
118 | ^^^^ explicit destructor calls not allowed
119 ```
120
121 This error message states that we’re not allowed to explicitly call `drop`. The
122 error message uses the term *destructor*, which is the general programming term
123 for a function that cleans up an instance. A *destructor* is analogous to a
124 *constructor* that creates an instance. The `drop` function in Rust is one
125 particular destructor.
126
127 Rust doesn’t let us call `drop` explicitly because Rust would still
128 automatically call `drop` on the value at the end of `main`. This would be a
129 *double free* error because Rust would be trying to clean up the same value
130 twice.
131
132 We can’t disable the automatic insertion of `drop` when a value goes out of
133 scope, and we can’t call the `drop` method explicitly. So, if we need to force
134 a value to be cleaned up early, we can use the `std::mem::drop` function.
135
136 The `std::mem::drop` function is different than the `drop` method in the `Drop`
137 trait. We call it by passing the value we want to force to be dropped early as
138 an argument. The function is in the prelude, so we can modify `main` in Listing
139 15-14 to call the `drop` function, as shown in Listing 15-16:
140
141 <span class="filename">Filename: src/main.rs</span>
142
143 ```rust
144 # struct CustomSmartPointer {
145 # data: String,
146 # }
147 #
148 # impl Drop for CustomSmartPointer {
149 # fn drop(&mut self) {
150 # println!("Dropping CustomSmartPointer!");
151 # }
152 # }
153 #
154 fn main() {
155 let c = CustomSmartPointer { data: String::from("some data") };
156 println!("CustomSmartPointer created.");
157 drop(c);
158 println!("CustomSmartPointer dropped before the end of main.");
159 }
160 ```
161
162 <span class="caption">Listing 15-16: Calling `std::mem::drop` to explicitly
163 drop a value before it goes out of scope</span>
164
165 Running this code will print the following:
166
167 ```text
168 CustomSmartPointer created.
169 Dropping CustomSmartPointer with data `some data`!
170 CustomSmartPointer dropped before the end of main.
171 ```
172
173 The text ```Dropping CustomSmartPointer with data `some data`!``` is printed
174 between the `CustomSmartPointer created.` and `CustomSmartPointer dropped
175 before the end of main.` text, showing that the `drop` method code is called to
176 drop `c` at that point.
177
178 We can use code specified in a `Drop` trait implementation in many ways to make
179 cleanup convenient and safe: for instance, we could use it to create our own
180 memory allocator! With the `Drop` trait and Rust’s ownership system, we don’t
181 have to remember to clean up because Rust does it automatically.
182
183 We also don’t have to worry about accidentally cleaning up values still in use
184 because that would cause a compiler error: the ownership system that makes sure
185 references are always valid also ensures that `drop` gets called only once when
186 the value is no longer being used.
187
188 Now that we’ve examined `Box<T>` and some of the characteristics of smart
189 pointers, let’s look at a few other smart pointers defined in the standard
190 library.