I am reading the source code of Box. Unable to understand that in Box Drop is defined as 'unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A>'. And the comment is "// the T in the Box is dropped by the compiler before the destructor is run".
The instance of Box own the data of T, but why "the T in the Box is dropped by the compiler before the destructor is run"?
Thanks!
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
#[inline]
fn drop(&mut self) {
// the T in the Box is dropped by the compiler before the destructor is run
let ptr = self.0;
unsafe {
let layout = Layout::for_value_raw(ptr.as_ptr());
if layout.size() != 0 {
self.1.deallocate(From::from(ptr.cast()), layout);
}
}
}
}
there is an unstable attribute that one can use to assert (unsafely) that a generic type's destructor is guaranteed to not access any expired data, even if its type gives it the capability to do so.
That attribute is called may_dangle and was introduced in RFC 1327.
I think it has something to do with Box's special ability to have stuff moved out of it:
struct Foo(i32);
let b = Box::new(Foo(42));
let x = *b; // Box can do this
drop(b); // This will not drop the Foo which is no longer in the Box (it is in x)
I would advise against doing this. Box is special cased in the compiler so its source code (in particular Deref and Drop) doesn't reflect what actually happens when you use it.
If you want to look at examples of using #[may_dangle] consider looking at Vec.
Ups ... you are right. But even without the explicit drop(b) someone has to deallocate the heap memory at the end of the scope. Seems the Box::drop does exactly that.