libs (data-types | machine | drop)
manually_drop
Include the ManuallyDrop
wrapper in core::mem
.
Currently Rust does not specify the order in which the destructors are run. Furthermore, this order differs depending on context. RFC issue #744 exposed the fact that the current, but unspecified behaviour is relied onto for code validity and that there’s at least a few instances of such code in the wild.
While a move to stabilise and document the order of destructor evaluation would technically fix the problem described above, there’s another important aspect to consider here – implicitness. Consider such code:
struct FruitBox {
peach: Peach,
banana: Banana,
}
Does this structure depend on Peach
’s destructor being run before Banana
for correctness?
Perhaps its the other way around and it is Banana
’s destructor that has to run first? In the
common case structures do not have any such dependencies between fields, and therefore it is easy
to overlook such a dependency while changing the code above to the snippet below (e.g. so the
fields are sorted by name).
struct FruitBox {
banana: Banana,
peach: Peach,
}
For structures with dependencies between fields it is worthwhile to have ability to explicitly annotate the dependencies somehow.
This RFC proposes adding the following struct
as a new lang item to the core::mem
(and by extension the std::mem
)
module. mem
module is a most suitable place for such type, as the module already a place for
functions very similar in purpose: drop
and forget
.
/// Inhibits compiler from automatically calling `T`’s destructor.
#[lang = "manually_drop"]
#[unstable(feature = "manually_drop", reason = "recently added", issue = "0")]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ManuallyDrop<T> {
value: T,
}
impl<T> ManuallyDrop<T> {
/// Wraps a value to be manually dropped.
#[unstable(feature = "manually_drop", reason = "recently added", issue = "0")]
pub fn new(value: T) -> ManuallyDrop<T> {
ManuallyDrop { value }
}
/// Extracts the value from the ManuallyDrop container.
#[unstable(feature = "manually_drop", reason = "recently added", issue = "0")]
pub fn into_inner(slot: ManuallyDrop<T>) -> T {
slot.value
}
/// Manually drops the contained value.
///
/// # Unsafety
///
/// This function runs the destructor of the contained value and thus makes any further action
/// with the value within invalid. The fact that this function does not consume the wrapper
/// does not statically prevent further reuse.
#[unstable(feature = "manually_drop", reason = "recently added", issue = "0")]
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
ptr::drop_in_place(&mut slot.value)
}
}
impl<T> Deref for ManuallyDrop<T> {
type Target = T;
// ...
}
impl<T> DerefMut for ManuallyDrop<T> {
// ...
}
The lang item will be treated specially by the compiler to not emit any drop glue for this type.
Let us apply ManuallyDrop
to a somewhat expanded example from the motivation:
struct FruitBox {
// Immediately clear there’s something non-trivial going on with these fields.
peach: ManuallyDrop<Peach>,
melon: Melon, // Field that’s independent of the other two.
banana: ManuallyDrop<Banana>,
}
impl Drop for FruitBox {
fn drop(&mut self) {
unsafe {
// Explicit ordering in which field destructors are run specified in the intuitive
// location – the destructor of the structure containing the fields.
// Moreover, one can now reorder fields within the struct however much they want.
ManuallyDrop::drop(&mut self.peach);
ManuallyDrop::drop(&mut self.banana);
}
// After destructor for `FruitBox` runs (this function), the destructor for Melon gets
// invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
}
}
It is proposed that this pattern would become idiomatic for structures where fields must be dropped in a particular order.
It is expected that the functions and wrapper added as a result of this RFC would be seldom necessary.
In addition to the usual API documentation, ManuallyDrop
should be mentioned in
reference/nomicon/elsewhere as the solution to the desire of explicit control of the order in which
the structure fields gets dropped.
None known.