3 What the language *does* provide is full-blown automatic destructors through the
4 `Drop` trait, which provides the following method:
10 This method gives the type time to somehow finish what it was doing. **After
11 `drop` is run, Rust will recursively try to drop all of the fields of `self`**.
12 This is a convenience feature so that you don't have to write "destructor
13 boilerplate" to drop children. If a struct has no special logic for being
14 dropped other than dropping its children, then it means `Drop` doesn't need to
15 be implemented at all!
17 **There is no stable way to prevent this behaviour in Rust 1.0.
19 Note that taking `&mut self` means that even if you *could* suppress recursive
20 Drop, Rust will prevent you from e.g. moving fields out of self. For most types,
23 For instance, a custom implementation of `Box` might write `Drop` like this:
26 #![feature(heap_api, core_intrinsics, unique)]
30 use std::intrinsics::drop_in_place;
33 struct Box<T>{ ptr: Unique<T> }
35 impl<T> Drop for Box<T> {
38 drop_in_place(*self.ptr);
39 heap::deallocate((*self.ptr) as *mut u8,
41 mem::align_of::<T>());
47 and this works fine because when Rust goes to drop the `ptr` field it just sees
48 a [Unique][] that has no actual `Drop` implementation. Similarly nothing can
49 use-after-free the `ptr` because when drop exits, it becomes inacessible.
51 However this wouldn't work:
54 #![feature(heap_api, core_intrinsics, unique)]
58 use std::intrinsics::drop_in_place;
61 struct Box<T>{ ptr: Unique<T> }
63 impl<T> Drop for Box<T> {
66 drop_in_place(*self.ptr);
67 heap::deallocate((*self.ptr) as *mut u8,
69 mem::align_of::<T>());
74 struct SuperBox<T> { my_box: Box<T> }
76 impl<T> Drop for SuperBox<T> {
79 // Hyper-optimized: deallocate the box's contents for it
80 // without `drop`ing the contents
81 heap::deallocate((*self.my_box.ptr) as *mut u8,
83 mem::align_of::<T>());
89 After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
90 happily proceed to tell the box to Drop itself and everything will blow up with
91 use-after-frees and double-frees.
93 Note that the recursive drop behaviour applies to *all* structs and enums
94 regardless of whether they implement Drop. Therefore something like
104 will have its data1 and data2's fields destructors whenever it "would" be
105 dropped, even though it itself doesn't implement Drop. We say that such a type
106 *needs Drop*, even though it is not itself Drop.
117 will have its inner Box field dropped *if and only if* an instance stores the
120 In general this works really nice because you don't need to worry about
121 adding/removing drops when you refactor your data layout. Still there's
122 certainly many valid usecases for needing to do trickier things with
125 The classic safe solution to overriding recursive drop and allowing moving out
126 of Self during `drop` is to use an Option:
129 #![feature(heap_api, core_intrinsics, unique)]
132 use std::ptr::Unique;
133 use std::intrinsics::drop_in_place;
136 struct Box<T>{ ptr: Unique<T> }
138 impl<T> Drop for Box<T> {
141 drop_in_place(*self.ptr);
142 heap::deallocate((*self.ptr) as *mut u8,
144 mem::align_of::<T>());
149 struct SuperBox<T> { my_box: Option<Box<T>> }
151 impl<T> Drop for SuperBox<T> {
154 // Hyper-optimized: deallocate the box's contents for it
155 // without `drop`ing the contents. Need to set the `box`
156 // field as `None` to prevent Rust from trying to Drop it.
157 let my_box = self.my_box.take().unwrap();
158 heap::deallocate((*my_box.ptr) as *mut u8,
160 mem::align_of::<T>());
167 However this has fairly odd semantics: you're saying that a field that *should*
168 always be Some may be None, just because that happens in the destructor. Of
169 course this conversely makes a lot of sense: you can call arbitrary methods on
170 self during the destructor, and this should prevent you from ever doing so after
171 deinitializing the field. Not that it will prevent you from producing any other
172 arbitrarily invalid state in there.
174 On balance this is an ok choice. Certainly what you should reach for by default.
175 However, in the future we expect there to be a first-class way to announce that
176 a field shouldn't be automatically dropped.
178 [Unique]: phantom-data.html