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.
12 **After `drop` is run, Rust will recursively try to drop all of the fields
15 This is a convenience feature so that you don't have to write "destructor
16 boilerplate" to drop children. If a struct has no special logic for being
17 dropped other than dropping its children, then it means `Drop` doesn't need to
18 be implemented at all!
20 **There is no stable way to prevent this behaviour in Rust 1.0.**
22 Note that taking `&mut self` means that even if you could suppress recursive
23 Drop, Rust will prevent you from e.g. moving fields out of self. For most types,
26 For instance, a custom implementation of `Box` might write `Drop` like this:
29 #![feature(heap_api, core_intrinsics, unique)]
33 use std::intrinsics::drop_in_place;
36 struct Box<T>{ ptr: Unique<T> }
38 impl<T> Drop for Box<T> {
41 drop_in_place(*self.ptr);
42 heap::deallocate((*self.ptr) as *mut u8,
44 mem::align_of::<T>());
50 and this works fine because when Rust goes to drop the `ptr` field it just sees
51 a [Unique][] that has no actual `Drop` implementation. Similarly nothing can
52 use-after-free the `ptr` because when drop exits, it becomes inacessible.
54 However this wouldn't work:
57 #![feature(heap_api, core_intrinsics, unique)]
61 use std::intrinsics::drop_in_place;
64 struct Box<T>{ ptr: Unique<T> }
66 impl<T> Drop for Box<T> {
69 drop_in_place(*self.ptr);
70 heap::deallocate((*self.ptr) as *mut u8,
72 mem::align_of::<T>());
77 struct SuperBox<T> { my_box: Box<T> }
79 impl<T> Drop for SuperBox<T> {
82 // Hyper-optimized: deallocate the box's contents for it
83 // without `drop`ing the contents
84 heap::deallocate((*self.my_box.ptr) as *mut u8,
86 mem::align_of::<T>());
92 After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
93 happily proceed to tell the box to Drop itself and everything will blow up with
94 use-after-frees and double-frees.
96 Note that the recursive drop behaviour applies to all structs and enums
97 regardless of whether they implement Drop. Therefore something like
107 will have its data1 and data2's fields destructors whenever it "would" be
108 dropped, even though it itself doesn't implement Drop. We say that such a type
109 *needs Drop*, even though it is not itself Drop.
120 will have its inner Box field dropped if and only if an instance stores the
123 In general this works really nice because you don't need to worry about
124 adding/removing drops when you refactor your data layout. Still there's
125 certainly many valid usecases for needing to do trickier things with
128 The classic safe solution to overriding recursive drop and allowing moving out
129 of Self during `drop` is to use an Option:
132 #![feature(heap_api, core_intrinsics, unique)]
135 use std::ptr::Unique;
136 use std::intrinsics::drop_in_place;
139 struct Box<T>{ ptr: Unique<T> }
141 impl<T> Drop for Box<T> {
144 drop_in_place(*self.ptr);
145 heap::deallocate((*self.ptr) as *mut u8,
147 mem::align_of::<T>());
152 struct SuperBox<T> { my_box: Option<Box<T>> }
154 impl<T> Drop for SuperBox<T> {
157 // Hyper-optimized: deallocate the box's contents for it
158 // without `drop`ing the contents. Need to set the `box`
159 // field as `None` to prevent Rust from trying to Drop it.
160 let my_box = self.my_box.take().unwrap();
161 heap::deallocate((*my_box.ptr) as *mut u8,
163 mem::align_of::<T>());
170 However this has fairly odd semantics: you're saying that a field that *should*
171 always be Some *may* be None, just because that happens in the destructor. Of
172 course this conversely makes a lot of sense: you can call arbitrary methods on
173 self during the destructor, and this should prevent you from ever doing so after
174 deinitializing the field. Not that it will prevent you from producing any other
175 arbitrarily invalid state in there.
177 On balance this is an ok choice. Certainly what you should reach for by default.
178 However, in the future we expect there to be a first-class way to announce that
179 a field shouldn't be automatically dropped.
181 [Unique]: phantom-data.html