I am aware of a similar question that was once asked, but I am still rather perplexed after reading the accepted answer (to be clear, I do not see why the compiler does not have a special case for Drop::drop
, as mentioned in the comments, since it already disallows moving out of an object that implements Drop
). So let me please try to reiterate on this.
Suppose we have a struct
Foo
that owns some resources; say, a thread that has to be joined when the object goes out of scope (this situation can happen if we are writing an asynchronous runtime):
struct Foo {
t: JoinHandle<()>,
}
Since std::ops::Drop::drop
takes &mut self
, with this definition we cannot really hope to join this thread in drop
, because JoinHandle::join
takes self
by value. Therefore, we have to resort to making this field optional:
struct Foo {
t: Option<JoinHandle<()>>,
}
And then we can go with if let Some(t) = self.t.take() { t.join(); }
. But there still seem to be some unanswered questions here:
Is the
drop
signature hinting us that thedrop
method may get called several times on some objects, or thatdrop
may not be the last method that is called on an object during its lifetime? If yes, in which scenarios can this happen? Is it correct to writeself.t.unwrap()
in the example above?How to achieve similar semantics without introducing the overhead of
Option
(which may not in all cases get covered by niche optimisation and is anyway rather verbose)?