]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch15-03-drop.md
New upstream version 1.40.0+dfsg1
[rustc.git] / src / doc / book / src / ch15-03-drop.md
1 ## Running Code on Cleanup with the `Drop` Trait
2
3 The second trait important to the smart pointer pattern is `Drop`, which lets
4 you customize what happens when a value is about to go out of scope. You can
5 provide an implementation for the `Drop` trait on any type, and the code you
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, you can specify that a
15 particular bit of code be run whenever a value goes out of scope, and the
16 compiler will insert this code automatically. As a result, you don’t need to be
17 careful about placing cleanup code everywhere in a program that an instance of
18 a particular type is finished with—you still won’t leak resources!
19
20 Specify the code to run when a value goes out of scope by implementing the
21 `Drop` trait. The `Drop` trait requires you to implement one method named
22 `drop` that takes a mutable reference to `self`. To see when Rust calls `drop`,
23 let’s 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 bring it into
54 scope. We 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 instances 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 instances went out of scope,
75 calling the code we specified. Variables are dropped in the reverse order of
76 their creation, so `d` was dropped before `c`. This example gives you a visual
77 guide to how the `drop` method works; usually you would specify the cleanup
78 code that your type needs to run rather than a print message.
79
80 ### Dropping a Value Early with `std::mem::drop`
81
82 Unfortunately, it’s not straightforward to disable the automatic `drop`
83 functionality. Disabling `drop` isn’t usually necessary; the whole point of the
84 `Drop` trait is that it’s taken care of automatically. Occasionally, however,
85 you might want to clean up a value early. One example is when using smart
86 pointers that manage locks: you might want to force the `drop` method that
87 releases the lock so that other code in the same scope can acquire the lock.
88 Rust doesn’t let you call the `Drop` trait’s `drop` method manually; instead
89 you have to call the `std::mem::drop` function provided by the standard library
90 if you want to force a value to be dropped before the end of its scope.
91
92 If we try to call the `Drop` trait’s `drop` method manually by modifying the
93 `main` function from Listing 15-14, as shown in Listing 15-15, we’ll get a
94 compiler error:
95
96 <span class="filename">Filename: src/main.rs</span>
97
98 ```rust,ignore,does_not_compile
99 fn main() {
100 let c = CustomSmartPointer { data: String::from("some data") };
101 println!("CustomSmartPointer created.");
102 c.drop();
103 println!("CustomSmartPointer dropped before the end of main.");
104 }
105 ```
106
107 <span class="caption">Listing 15-15: Attempting to call the `drop` method from
108 the `Drop` trait manually to clean up early</span>
109
110 When we try to compile this code, we’ll get this error:
111
112 ```text
113 error[E0040]: explicit use of destructor method
114 --> src/main.rs:14:7
115 |
116 14 | c.drop();
117 | ^^^^ explicit destructor calls not allowed
118 ```
119
120 This error message states that we’re not allowed to explicitly call `drop`. The
121 error message uses the term *destructor*, which is the general programming term
122 for a function that cleans up an instance. A *destructor* is analogous to a
123 *constructor*, which creates an instance. The `drop` function in Rust is one
124 particular destructor.
125
126 Rust doesn’t let us call `drop` explicitly because Rust would still
127 automatically call `drop` on the value at the end of `main`. This would be a
128 *double free* error because Rust would be trying to clean up the same value
129 twice.
130
131 We can’t disable the automatic insertion of `drop` when a value goes out of
132 scope, and we can’t call the `drop` method explicitly. So, if we need to force
133 a value to be cleaned up early, we can use the `std::mem::drop` function.
134
135 The `std::mem::drop` function is different from the `drop` method in the `Drop`
136 trait. We call it by passing the value we want to force to be dropped early as
137 an argument. The function is in the prelude, so we can modify `main` in Listing
138 15-15 to call the `drop` function, as shown in Listing 15-16:
139
140 <span class="filename">Filename: src/main.rs</span>
141
142 ```rust
143 # struct CustomSmartPointer {
144 # data: String,
145 # }
146 #
147 # impl Drop for CustomSmartPointer {
148 # fn drop(&mut self) {
149 # println!("Dropping CustomSmartPointer with data `{}`!", self.data);
150 # }
151 # }
152 #
153 fn main() {
154 let c = CustomSmartPointer { data: String::from("some data") };
155 println!("CustomSmartPointer created.");
156 drop(c);
157 println!("CustomSmartPointer dropped before the end of main.");
158 }
159 ```
160
161 <span class="caption">Listing 15-16: Calling `std::mem::drop` to explicitly
162 drop a value before it goes out of scope</span>
163
164 Running this code will print the following:
165
166 ```text
167 CustomSmartPointer created.
168 Dropping CustomSmartPointer with data `some data`!
169 CustomSmartPointer dropped before the end of main.
170 ```
171
172 The text ```Dropping CustomSmartPointer with data `some data`!``` is printed
173 between the `CustomSmartPointer created.` and `CustomSmartPointer dropped
174 before the end of main.` text, showing that the `drop` method code is called to
175 drop `c` at that point.
176
177 You can use code specified in a `Drop` trait implementation in many ways to
178 make cleanup convenient and safe: for instance, you could use it to create your
179 own memory allocator! With the `Drop` trait and Rust’s ownership system, you
180 don’t have to remember to clean up because Rust does it automatically.
181
182 You also don’t have to worry about problems resulting from accidentally
183 cleaning up values still in use: the ownership system that makes sure
184 references are always valid also ensures that `drop` gets called only once when
185 the value is no longer being used.
186
187 Now that we’ve examined `Box<T>` and some of the characteristics of smart
188 pointers, let’s look at a few other smart pointers defined in the standard
189 library.