Skip to content

Commit 7009e6d

Browse files
committed
mem::forget docs: mention ManuallyDrop
1 parent 5e380b7 commit 7009e6d

File tree

1 file changed

+33
-3
lines changed

1 file changed

+33
-3
lines changed

src/libcore/mem/mod.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ pub use crate::intrinsics::transmute;
4545
/// `mem::forget` from safe code does not fundamentally change Rust's safety
4646
/// guarantees.
4747
///
48-
/// That said, leaking resources such as memory or I/O objects is usually undesirable,
49-
/// so `forget` is only recommended for specialized use cases like those shown below.
48+
/// That said, leaking resources such as memory or I/O objects is usually undesirable.
49+
/// The need comes up in some specialized use cases for FFI or unsafe code, but even
50+
/// then, [`ManuallyDrop`] is typically preferred.
5051
///
5152
/// Because forgetting a value is allowed, any `unsafe` code you write must
5253
/// allow for this possibility. You cannot return a value and expect that the
@@ -68,7 +69,35 @@ pub use crate::intrinsics::transmute;
6869
/// ```
6970
///
7071
/// The practical use cases for `forget` are rather specialized and mainly come
71-
/// up in unsafe or FFI code.
72+
/// up in unsafe or FFI code. However, [`ManuallyDrop`] is usually preferred
73+
/// for such cases, e.g.:
74+
///
75+
/// ```
76+
/// use std::mem::ManuallyDrop;
77+
///
78+
/// let v = vec![65, 122];
79+
/// // Before we disassemble `v` into its raw parts, make sure it
80+
/// // does not get dropped!
81+
/// let mut v = ManuallyDrop::new(v);
82+
/// // Now disassemble `v`. These operations cannot panic, so there cannot be a leak.
83+
/// let ptr = v.as_mut_ptr();
84+
/// let cap = v.capacity();
85+
/// // Finally, build a `String`.
86+
/// let s = unsafe { String::from_raw_parts(ptr, 2, cap) };
87+
/// assert_eq!(s, "Az");
88+
/// // `s` is implicitly dropped and its memory deallocated.
89+
/// ```
90+
///
91+
/// Using `ManuallyDrop` here has two advantages:
92+
///
93+
/// * We do not "touch" `v` after disassembling it. For some types, operations
94+
/// such as passing ownership (to a funcion like `mem::forget`) requires them to actually
95+
/// be fully owned right now; that is a promise we do not want to make here as we are
96+
/// in the process of transferring ownership to the new `String` we are building.
97+
/// * In case of an unexpected panic, `ManuallyDrop` is not dropped, but if the panic
98+
/// occurs before `mem::forget` was called we might end up dropping invalid data,
99+
/// or double-dropping. In other words, `ManuallyDrop` errs on the side of leaking
100+
/// instead of erring on the side of dropping.
72101
///
73102
/// [drop]: fn.drop.html
74103
/// [uninit]: fn.uninitialized.html
@@ -78,6 +107,7 @@ pub use crate::intrinsics::transmute;
78107
/// [leak]: ../../std/boxed/struct.Box.html#method.leak
79108
/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
80109
/// [ub]: ../../reference/behavior-considered-undefined.html
110+
/// [`ManuallyDrop`]: struct.ManuallyDrop.html
81111
#[inline]
82112
#[stable(feature = "rust1", since = "1.0.0")]
83113
pub fn forget<T>(t: T) {

0 commit comments

Comments
 (0)