|
49 | 49 | //! v[1] = v[1] + 5;
|
50 | 50 | //! ```
|
51 | 51 | //!
|
| 52 | +//! # Memory layout |
| 53 | +//! |
| 54 | +//! When the type is non-zero-sized and the capacity is nonzero, [`Vec`] uses the [`Global`] |
| 55 | +//! allocator for its allocation. It is valid to convert both ways between such a [`Vec`] and a raw |
| 56 | +//! pointer allocated with the [`Global`] allocator, provided that the [`Layout`] used with the |
| 57 | +//! allocator is correct for a sequence of `capacity` elements of the type, and the first `len` |
| 58 | +//! values pointed to by the raw pointer are valid. More precisely, a `ptr: *mut T` that has been |
| 59 | +//! allocated with the [`Global`] allocator with [`Layout::array::<T>(capacity)`][Layout::array] may |
| 60 | +//! be converted into a vec using |
| 61 | +//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). Conversely, the memory |
| 62 | +//! backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be deallocated using the |
| 63 | +//! [`Global`] allocator with the same layout. |
| 64 | +//! |
| 65 | +//! For zero-sized types (ZSTs), or when the capacity is zero, the `Vec` pointer must be non-null |
| 66 | +//! and sufficiently aligned. The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be |
| 67 | +//! used is to use [`ptr::NonNull::dangling`]. |
| 68 | +//! |
52 | 69 | //! [`push`]: Vec::push
|
| 70 | +//! [`ptr::NonNull::dangling`]: NonNull::dangling |
| 71 | +//! [`Layout`]: crate::alloc::Layout |
| 72 | +//! [Layout::array]: crate::alloc::Layout::array |
53 | 73 |
|
54 | 74 | #![stable(feature = "rust1", since = "1.0.0")]
|
55 | 75 |
|
@@ -523,18 +543,23 @@ impl<T> Vec<T> {
|
523 | 543 | /// This is highly unsafe, due to the number of invariants that aren't
|
524 | 544 | /// checked:
|
525 | 545 | ///
|
526 |
| - /// * `ptr` must have been allocated using the global allocator, such as via |
527 |
| - /// the [`alloc::alloc`] function. |
528 |
| - /// * `T` needs to have the same alignment as what `ptr` was allocated with. |
| 546 | + /// * If `T` is not a zero-sized type and the capacity is nonzero, `ptr` must have |
| 547 | + /// been allocated using the global allocator, such as via the [`alloc::alloc`] |
| 548 | + /// function. If `T` is a zero-sized type or the capacity is zero, `ptr` need |
| 549 | + /// only be non-null and aligned. |
| 550 | + /// * `T` needs to have the same alignment as what `ptr` was allocated with, |
| 551 | + /// if the pointer is required to be allocated. |
529 | 552 | /// (`T` having a less strict alignment is not sufficient, the alignment really
|
530 | 553 | /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
531 | 554 | /// allocated and deallocated with the same layout.)
|
532 |
| - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs |
533 |
| - /// to be the same size as the pointer was allocated with. (Because similar to |
534 |
| - /// alignment, [`dealloc`] must be called with the same layout `size`.) |
| 555 | + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if |
| 556 | + /// nonzero, needs to be the same size as the pointer was allocated with. |
| 557 | + /// (Because similar to alignment, [`dealloc`] must be called with the same |
| 558 | + /// layout `size`.) |
535 | 559 | /// * `length` needs to be less than or equal to `capacity`.
|
536 | 560 | /// * The first `length` values must be properly initialized values of type `T`.
|
537 |
| - /// * `capacity` needs to be the capacity that the pointer was allocated with. |
| 561 | + /// * `capacity` needs to be the capacity that the pointer was allocated with, |
| 562 | + /// if the pointer is required to be allocated. |
538 | 563 | /// * The allocated size in bytes must be no larger than `isize::MAX`.
|
539 | 564 | /// See the safety documentation of [`pointer::offset`].
|
540 | 565 | ///
|
@@ -770,12 +795,16 @@ impl<T> Vec<T> {
|
770 | 795 | /// order as the arguments to [`from_raw_parts`].
|
771 | 796 | ///
|
772 | 797 | /// 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. |
| 798 | + /// memory previously managed by the `Vec`. Most often, one does |
| 799 | + /// this by converting the raw pointer, length, and capacity back |
| 800 | + /// into a `Vec` with the [`from_raw_parts`] function; more generally, |
| 801 | + /// if `T` is non-zero-sized and the capacity is nonzero, one may use |
| 802 | + /// any method that calls [`dealloc`] with a layout of |
| 803 | + /// `Layout::array::<T>(capacity)`; if `T` is zero-sized or the |
| 804 | + /// capacity is zero, nothing needs to be done. |
777 | 805 | ///
|
778 | 806 | /// [`from_raw_parts`]: Vec::from_raw_parts
|
| 807 | + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc |
779 | 808 | ///
|
780 | 809 | /// # Examples
|
781 | 810 | ///
|
@@ -1755,6 +1784,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
1755 | 1784 | /// may still invalidate this pointer.
|
1756 | 1785 | /// See the second example below for how this guarantee can be used.
|
1757 | 1786 | ///
|
| 1787 | + /// The method also guarantees that, as long as `T` is not zero-sized and the capacity is |
| 1788 | + /// nonzero, the pointer may be passed into [`dealloc`] with a layout of |
| 1789 | + /// `Layout::array::<T>(capacity)` in order to deallocate the backing memory. If this is done, |
| 1790 | + /// be careful not to run the destructor of the `Vec`, as dropping it will result in |
| 1791 | + /// double-frees. Wrapping the `Vec` in a [`ManuallyDrop`] is the typical way to achieve this. |
| 1792 | + /// |
1758 | 1793 | /// # Examples
|
1759 | 1794 | ///
|
1760 | 1795 | /// ```
|
@@ -1787,9 +1822,24 @@ impl<T, A: Allocator> Vec<T, A> {
|
1787 | 1822 | /// }
|
1788 | 1823 | /// ```
|
1789 | 1824 | ///
|
| 1825 | + /// Deallocating a vector using [`Box`] (which uses [`dealloc`] internally): |
| 1826 | + /// |
| 1827 | + /// ``` |
| 1828 | + /// use std::mem::{ManuallyDrop, MaybeUninit}; |
| 1829 | + /// |
| 1830 | + /// let mut v = ManuallyDrop::new(vec![0, 1, 2]); |
| 1831 | + /// let ptr = v.as_mut_ptr(); |
| 1832 | + /// let capacity = v.capacity(); |
| 1833 | + /// let slice_ptr: *mut [MaybeUninit<i32>] = |
| 1834 | + /// std::ptr::slice_from_raw_parts_mut(ptr.cast(), capacity); |
| 1835 | + /// drop(unsafe { Box::from_raw(slice_ptr) }); |
| 1836 | + /// ``` |
| 1837 | + /// |
1790 | 1838 | /// [`as_mut_ptr`]: Vec::as_mut_ptr
|
1791 | 1839 | /// [`as_ptr`]: Vec::as_ptr
|
1792 | 1840 | /// [`as_non_null`]: Vec::as_non_null
|
| 1841 | + /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc |
| 1842 | + /// [`ManuallyDrop`]: core::mem::ManuallyDrop |
1793 | 1843 | #[stable(feature = "vec_as_ptr", since = "1.37.0")]
|
1794 | 1844 | #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
|
1795 | 1845 | #[rustc_never_returns_null_ptr]
|
|
0 commit comments