|
49 | 49 | //! v[1] = v[1] + 5;
|
50 | 50 | //! ```
|
51 | 51 | //!
|
| 52 | +//! # Memory layout |
| 53 | +//! |
| 54 | +//! For non-zero-sized types, [`Vec`] uses the [`Global`] allocator for its allocation. It is |
| 55 | +//! valid to convert both ways between a [`Vec`] and a raw pointer allocated with the [`Global`] |
| 56 | +//! allocator, provided that the [`Layout`] used with the allocator is correct for a sequence of |
| 57 | +//! `capacity` elements of the type, and the first `len` values pointed to by the raw pointer are |
| 58 | +//! valid. More precisely, a `ptr: *mut T` that has been allocated with the [`Global`] allocator |
| 59 | +//! with [`Layout::array::<T>(capacity)`][Layout::array] may be converted into a vec using |
| 60 | +//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). |
| 61 | +//! Conversely, the memory backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be |
| 62 | +//! deallocated using the [`Global`] allocator with the same layout. |
| 63 | +//! |
| 64 | +//! For zero-sized types (ZSTs), the `Vec` pointer must be non-null and sufficiently aligned. |
| 65 | +//! The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be used is to use |
| 66 | +//! [`ptr::NonNull::dangling`]. |
| 67 | +//! |
52 | 68 | //! [`push`]: Vec::push
|
| 69 | +//! [`ptr::NonNull::dangling`]: NonNull::dangling |
| 70 | +//! [`Layout`]: crate::alloc::Layout |
| 71 | +//! [Layout::array]: crate::alloc::Layout::array |
53 | 72 |
|
54 | 73 | #![stable(feature = "rust1", since = "1.0.0")]
|
55 | 74 |
|
@@ -770,12 +789,15 @@ impl<T> Vec<T> {
|
770 | 789 | /// order as the arguments to [`from_raw_parts`].
|
771 | 790 | ///
|
772 | 791 | /// After calling this function, the caller is responsible for the
|
773 |
| - /// memory previously managed by the `Vec`. The only way to do |
774 |
| - /// this is to convert the raw pointer, length, and capacity back |
775 |
| - /// into a `Vec` with the [`from_raw_parts`] function, allowing |
776 |
| - /// the destructor to perform the cleanup. |
| 792 | + /// memory previously managed by the `Vec`. Most often, one does |
| 793 | + /// this by converting the raw pointer, length, and capacity back |
| 794 | + /// into a `Vec` with the [`from_raw_parts`] function; more generally, |
| 795 | + /// if `T` is non-zero-sized one may use any method that calls |
| 796 | + /// [`dealloc`] with a layout of `Layout::array::<T>(capacity)`, |
| 797 | + /// and if `T` is zero-sized nothing needs to be done. |
777 | 798 | ///
|
778 | 799 | /// [`from_raw_parts`]: Vec::from_raw_parts
|
| 800 | + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc |
779 | 801 | ///
|
780 | 802 | /// # Examples
|
781 | 803 | ///
|
@@ -1755,6 +1777,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
1755 | 1777 | /// may still invalidate this pointer.
|
1756 | 1778 | /// See the second example below for how this guarantee can be used.
|
1757 | 1779 | ///
|
| 1780 | + /// The method also guarantees that, as long as `T` is not zero-sized, the pointer may be |
| 1781 | + /// passed into [`dealloc`] with a layout of `Layout::array::<T>(capacity)` in order to |
| 1782 | + /// deallocate the backing memory. If this is done, be careful not to run the destructor |
| 1783 | + /// of the `Vec`, as dropping it will result in double-frees. Wrapping the `Vec` in a |
| 1784 | + /// [`ManuallyDrop`] is the typical way to achieve this. |
| 1785 | + /// |
1758 | 1786 | /// # Examples
|
1759 | 1787 | ///
|
1760 | 1788 | /// ```
|
@@ -1787,9 +1815,24 @@ impl<T, A: Allocator> Vec<T, A> {
|
1787 | 1815 | /// }
|
1788 | 1816 | /// ```
|
1789 | 1817 | ///
|
| 1818 | + /// Deallocating a vector using [`Box`] (which uses [`dealloc`] internally): |
| 1819 | + /// |
| 1820 | + /// ``` |
| 1821 | + /// use std::mem::{ManuallyDrop, MaybeUninit}; |
| 1822 | + /// |
| 1823 | + /// let mut v = ManuallyDrop::new(vec![0, 1, 2]); |
| 1824 | + /// let ptr = v.as_mut_ptr(); |
| 1825 | + /// let capacity = v.capacity(); |
| 1826 | + /// let slice_ptr: *mut [MaybeUninit<i32>] = |
| 1827 | + /// std::ptr::slice_from_raw_parts_mut(ptr.cast(), capacity); |
| 1828 | + /// drop(unsafe { Box::from_raw(slice_ptr) }); |
| 1829 | + /// ``` |
| 1830 | + /// |
1790 | 1831 | /// [`as_mut_ptr`]: Vec::as_mut_ptr
|
1791 | 1832 | /// [`as_ptr`]: Vec::as_ptr
|
1792 | 1833 | /// [`as_non_null`]: Vec::as_non_null
|
| 1834 | + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc |
| 1835 | + /// [`ManuallyDrop`]: core::mem::ManuallyDrop |
1793 | 1836 | #[stable(feature = "vec_as_ptr", since = "1.37.0")]
|
1794 | 1837 | #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
|
1795 | 1838 | #[rustc_never_returns_null_ptr]
|
|
0 commit comments