Why does Drop
’s method have signature fn drop(&mut self)
instead of fn drop(self)
? This makes it difficult to move values out of the fields e.g. self.join_handle.join()
or std::mem::drop(self.file)
(error: cannot move out of type X
, which defines the Drop
trait).
2 Answers
Let's look at how std::mem::drop
is implemented:
pub fn drop<T>(_x: T) { }
That's right: it's an empty function! That's because it takes advantage of move semantics to acquire ownership of its argument. If T
implements Drop
, the compiler automatically inserts a call to Drop::drop(_x)
at the end of the function. This happens to all arguments received by value (that is, in fact, all arguments whatsoever, but dropping a reference doesn't drop the referent).
Now consider what would happen if Drop::drop
took its argument by value: the compiler would try to invoke Drop::drop
on the argument within Drop::drop
— this would cause a stack overflow! And of course, you would be able to call mem::drop
on the argument, which would also try to recursively call Drop::drop
.

- 13,815
- 8
- 40
- 72

- 60,274
- 7
- 180
- 155
-
24Sure, but the compiler could easily special case this case. – Lucretiel Feb 09 '20 at 20:59
-
8This answer begs the question. The only reason `std::mem::drop` exists at all is so that the caller is forced to give up ownership before `drop` is called. If `drop` accepted `self` directly there would be no need for `std::mem::drop`. – GManNickG Dec 30 '20 at 23:50
-
@GManNickG: there is *absolutely nothing* special about `std::mem::drop`. The only reason it exists at all is for *convenience*, because occasionally you need to drop something (e.g. a lock guard), and `drop(guard);` is prettier than `let _x = guard;`. That `std::ops::Drop::drop` and `std::mem::drop` have the same name is essentially coincidence. – Chris Morgan Mar 11 '23 at 16:14
Actually, it is unnecessary for Drop::drop
to take ownership of the value.
In Rust, ownership is automatically handled at language level, and therefore the compiler makes sure to properly implement ownership semantics; thus when a Foo { a: int, b: String }
goes out of scope, the compiler will drop Foo
by dropping its inner fields automatically.
It is thus unnecessary for Drop::drop
to drop the fields!
Actually, after Drop::drop
is called on Foo
, the compiler will itself mem::drop
the different fields (which may also invoke Drop::drop
on those fields which define it, such as b: String
here).
What does Drop::drop
do, then?
It is used to implement extra logic on top of what the compiler will do; taking your JoinHandle
example:
#[stable(feature = "rust1", since = "1.0.0")]
#[unsafe_destructor]
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
if !self.0.joined {
unsafe { imp::detach(self.0.native) }
}
}
}
Here, Drop::drop
is used to detach the thread, for example.
In a collection such as Vec::vec
:
#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
// This is (and should always remain) a no-op if the fields are
// zeroed (when moving out, because of #[unsafe_no_drop_flag]).
if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
unsafe {
for x in &*self {
ptr::read(x);
}
dealloc(*self.ptr, self.cap)
}
}
}
}
Here, as the raw memory is manipulated in a way opaque to the compiler, this implementation takes care of:
- Dropping each element held by the vector
- Deallocating the memory

- 11,726
- 7
- 55
- 77

- 287,565
- 48
- 449
- 722
-
5Sorry, I wasn’t clear. I do not intend to manually delete each field. My intention is to call functions that consume some of my fields so that I can wait on a thread or log any errors (I admit that I shouldn’t have brought up `std::mem::drop` which doesn’t tell you any errors that happened). – yonran Jun 18 '15 at 06:32
-
1@yonran: Well, asking for a rationale as you did is a valid question so I am reluctant to tell you to edit it and completely change it, instead I would advise you to simply ask another question on how to do what you want to do, preferably with a MCVE on [the playpen](https://play.rust-lang.org/) that we can tinker with to make sure our solution does compile. – Matthieu M. Jun 18 '15 at 06:40
-
1@yonran: Did you ever ask another question? I'm having exactly the same problem as you; specifically with using [`WavWriter::finalize()`](https://docs.rs/hound/3.0.0/hound/struct.WavWriter.html#method.finalize) in a `Drop()`. – Timmmm Dec 26 '16 at 21:30
-
1@Timmmm, sorry, no I didn’t. I think I just used an `Option
` in order to consume it during `drop`. – yonran Dec 26 '16 at 23:11