|
51 | 51 | //!
|
52 | 52 | //! # Memory layout
|
53 | 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. |
| 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. |
63 | 64 | //!
|
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`]. |
| 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`]. |
67 | 68 | //!
|
68 | 69 | //! [`push`]: Vec::push
|
69 | 70 | //! [`ptr::NonNull::dangling`]: NonNull::dangling
|
@@ -542,18 +543,23 @@ impl<T> Vec<T> {
|
542 | 543 | /// This is highly unsafe, due to the number of invariants that aren't
|
543 | 544 | /// checked:
|
544 | 545 | ///
|
545 |
| - /// * `ptr` must have been allocated using the global allocator, such as via |
546 |
| - /// the [`alloc::alloc`] function. |
547 |
| - /// * `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. |
548 | 552 | /// (`T` having a less strict alignment is not sufficient, the alignment really
|
549 | 553 | /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
550 | 554 | /// allocated and deallocated with the same layout.)
|
551 |
| - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs |
552 |
| - /// to be the same size as the pointer was allocated with. (Because similar to |
553 |
| - /// 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`.) |
554 | 559 | /// * `length` needs to be less than or equal to `capacity`.
|
555 | 560 | /// * The first `length` values must be properly initialized values of type `T`.
|
556 |
| - /// * `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. |
557 | 563 | /// * The allocated size in bytes must be no larger than `isize::MAX`.
|
558 | 564 | /// See the safety documentation of [`pointer::offset`].
|
559 | 565 | ///
|
@@ -792,9 +798,10 @@ impl<T> Vec<T> {
|
792 | 798 | /// memory previously managed by the `Vec`. Most often, one does
|
793 | 799 | /// this by converting the raw pointer, length, and capacity back
|
794 | 800 | /// 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. |
| 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. |
798 | 805 | ///
|
799 | 806 | /// [`from_raw_parts`]: Vec::from_raw_parts
|
800 | 807 | /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
@@ -1777,11 +1784,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
1777 | 1784 | /// may still invalidate this pointer.
|
1778 | 1785 | /// See the second example below for how this guarantee can be used.
|
1779 | 1786 | ///
|
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. |
| 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. |
1785 | 1792 | ///
|
1786 | 1793 | /// # Examples
|
1787 | 1794 | ///
|
|
0 commit comments