Skip to content

Commit a7e1431

Browse files
committed
Update boxed::Box docs on memory layout
1 parent 589beb9 commit a7e1431

File tree

1 file changed

+45
-14
lines changed

1 file changed

+45
-14
lines changed

src/liballoc/boxed.rs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,38 @@ impl<T: ?Sized> Box<T> {
127127
///
128128
/// After calling this function, the raw pointer is owned by the
129129
/// resulting `Box`. Specifically, the `Box` destructor will call
130-
/// the destructor of `T` and free the allocated memory. Since the
131-
/// way `Box` allocates and releases memory is unspecified, the
132-
/// only valid pointer to pass to this function is the one taken
133-
/// from another `Box` via the [`Box::into_raw`] function.
130+
/// the destructor of `T` and free the allocated memory. For this
131+
/// to be safe, the memory must have been allocated in the precise
132+
/// way that `Box` expects, namely, using the global allocator
133+
/// with the correct [`Layout`] for holding a value of type `T`. In
134+
/// particular, this will be satisfied for a pointer obtained
135+
/// from a previously existing `Box` using [`Box::into_raw`].
136+
///
137+
/// # Safety
134138
///
135139
/// This function is unsafe because improper use may lead to
136140
/// memory problems. For example, a double-free may occur if the
137141
/// function is called twice on the same raw pointer.
138142
///
139-
/// [`Box::into_raw`]: struct.Box.html#method.into_raw
140-
///
141143
/// # Examples
142-
///
144+
/// Recreate a `Box` which was previously converted to a raw pointer using [`Box::into_raw`]:
143145
/// ```
144146
/// let x = Box::new(5);
145147
/// let ptr = Box::into_raw(x);
146148
/// let x = unsafe { Box::from_raw(ptr) };
147149
/// ```
150+
/// Manually create a `Box` from scratch by using the global allocator:
151+
/// ```
152+
/// use std::alloc::{Layout, alloc};
153+
///
154+
/// let ptr = unsafe{ alloc(Layout::new::<i32>()) } as *mut i32;
155+
/// unsafe{ *ptr = 5; }
156+
/// let x = unsafe{ Box::from_raw(ptr) };
157+
/// ```
158+
///
159+
/// [`Layout`]: ../alloc/struct.Layout.html
160+
/// [`Box::into_raw`]: struct.Box.html#method.into_raw
161+
///
148162
#[stable(feature = "box_raw", since = "1.4.0")]
149163
#[inline]
150164
pub unsafe fn from_raw(raw: *mut T) -> Self {
@@ -158,21 +172,34 @@ impl<T: ?Sized> Box<T> {
158172
/// After calling this function, the caller is responsible for the
159173
/// memory previously managed by the `Box`. In particular, the
160174
/// caller should properly destroy `T` and release the memory. The
161-
/// proper way to do so is to convert the raw pointer back into a
162-
/// `Box` with the [`Box::from_raw`] function.
175+
/// easiest way to do so is to convert the raw pointer back into a `Box`
176+
/// with the [`Box::from_raw`] function.
163177
///
164178
/// Note: this is an associated function, which means that you have
165179
/// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
166180
/// is so that there is no conflict with a method on the inner type.
167181
///
168-
/// [`Box::from_raw`]: struct.Box.html#method.from_raw
169-
///
170182
/// # Examples
171-
///
183+
/// Converting the raw pointer back into a `Box` with [`Box::from_raw`]
184+
/// for automatic cleanup:
172185
/// ```
173-
/// let x = Box::new(5);
186+
/// let x = Box::new(String::from("Hello"));
174187
/// let ptr = Box::into_raw(x);
188+
/// let x = unsafe{ Box::from_raw(ptr) };
189+
/// ```
190+
/// Manual cleanup by running the destructor and deallocating the memory:
175191
/// ```
192+
/// use std::alloc::{Layout, dealloc};
193+
/// use std::ptr;
194+
///
195+
/// let x = Box::new(String::from("Hello"));
196+
/// let p = Box::into_raw(x);
197+
/// unsafe{ ptr::drop_in_place(p); }
198+
/// unsafe{ dealloc(p as *mut u8, Layout::new::<String>()); }
199+
/// ```
200+
///
201+
/// [`Box::from_raw`]: struct.Box.html#method.from_raw
202+
///
176203
#[stable(feature = "box_raw", since = "1.4.0")]
177204
#[inline]
178205
pub fn into_raw(b: Box<T>) -> *mut T {
@@ -184,7 +211,7 @@ impl<T: ?Sized> Box<T> {
184211
/// After calling this function, the caller is responsible for the
185212
/// memory previously managed by the `Box`. In particular, the
186213
/// caller should properly destroy `T` and release the memory. The
187-
/// proper way to do so is to convert the `NonNull<T>` pointer
214+
/// easiest way to do so is to convert the `NonNull<T>` pointer
188215
/// into a raw pointer and back into a `Box` with the [`Box::from_raw`]
189216
/// function.
190217
///
@@ -203,6 +230,10 @@ impl<T: ?Sized> Box<T> {
203230
/// fn main() {
204231
/// let x = Box::new(5);
205232
/// let ptr = Box::into_raw_non_null(x);
233+
///
234+
/// // Clean up the memory by converting the NonNull pointer back
235+
/// // into a Box and letting the Box be dropped.
236+
/// let x = unsafe{ Box::from_raw(ptr.as_ptr()) };
206237
/// }
207238
/// ```
208239
#[unstable(feature = "box_into_raw_non_null", issue = "47336")]

0 commit comments

Comments
 (0)