Stop mentioning dropck and `PhantomData<T>` in the vec chapter

The usage of `PhantomData<T>` in this chapter is wrong and useless.
It's only needed when you have an unstable `#[may_dangle` on `Drop`.
Since the `phantom-data` chapter talks about this extensively, link
to it for more info and stop using `PhantomData<T>` for dropck in the
vec chapter.
pull/381/head
Nilstrieb 3 years ago
parent 9c73283775
commit d7d11b01df
No known key found for this signature in database

@ -28,7 +28,6 @@ impl<T> Vec<T> {
ptr: NonNull::dangling(), ptr: NonNull::dangling(),
len: 0, len: 0,
cap: 0, cap: 0,
_marker: PhantomData,
} }
} }
} }

@ -10,7 +10,6 @@ use std::ptr::{self, NonNull};
struct RawVec<T> { struct RawVec<T> {
ptr: NonNull<T>, ptr: NonNull<T>,
cap: usize, cap: usize,
_marker: PhantomData<T>,
} }
unsafe impl<T: Send> Send for RawVec<T> {} unsafe impl<T: Send> Send for RawVec<T> {}
@ -25,7 +24,6 @@ impl<T> RawVec<T> {
RawVec { RawVec {
ptr: NonNull::dangling(), ptr: NonNull::dangling(),
cap: cap, cap: cap,
_marker: PhantomData,
} }
} }

@ -49,7 +49,6 @@ pub struct IntoIter<T> {
cap: usize, cap: usize,
start: *const T, start: *const T,
end: *const T, end: *const T,
_marker: PhantomData<T>,
} }
``` ```
@ -80,7 +79,6 @@ impl<T> IntoIterator for Vec<T> {
} else { } else {
ptr.as_ptr().add(len) ptr.as_ptr().add(len)
}, },
_marker: PhantomData,
} }
} }
} }

@ -15,13 +15,10 @@ pub struct Vec<T> {
} }
``` ```
And indeed this would compile. Unfortunately, it would be incorrect. First, the And indeed this would compile. Unfortunately, it would be too strict. The
compiler will give us too strict variance. So a `&Vec<&'static str>` compiler will give us too strict variance. So a `&Vec<&'static str>`
couldn't be used where an `&Vec<&'a str>` was expected. More importantly, it couldn't be used where an `&Vec<&'a str>` was expected. See [the chapter
will give incorrect ownership information to the drop checker, as it will on ownership and lifetimes][ownership] for all the details on variance.
conservatively assume we don't own any values of type `T`. See [the chapter
on ownership and lifetimes][ownership] for all the details on variance and
drop check.
As we saw in the ownership chapter, the standard library uses `Unique<T>` in place of As we saw in the ownership chapter, the standard library uses `Unique<T>` in place of
`*mut T` when it has a raw pointer to an allocation that it owns. Unique is unstable, `*mut T` when it has a raw pointer to an allocation that it owns. Unique is unstable,
@ -30,16 +27,16 @@ so we'd like to not use it if possible, though.
As a recap, Unique is a wrapper around a raw pointer that declares that: As a recap, Unique is a wrapper around a raw pointer that declares that:
* We are covariant over `T` * We are covariant over `T`
* We may own a value of type `T` (for drop check) * We may own a value of type `T` (this is not relevant for our example here, but see
[the chapter on PhantomData][phantom-data] on why the real `std::vec::Vec<T>` needs this)
* We are Send/Sync if `T` is Send/Sync * We are Send/Sync if `T` is Send/Sync
* Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized) * Our pointer is never null (so `Option<Vec<T>>` is null-pointer-optimized)
We can implement all of the above requirements in stable Rust. To do this, instead We can implement all of the above requirements in stable Rust. To do this, instead
of using `Unique<T>` we will use [`NonNull<T>`][NonNull], another wrapper around a of using `Unique<T>` we will use [`NonNull<T>`][NonNull], another wrapper around a
raw pointer, which gives us two of the above properties, namely it is covariant raw pointer, which gives us two of the above properties, namely it is covariant
over `T` and is declared to never be null. By adding a `PhantomData<T>` (for drop over `T` and is declared to never be null. By implementing Send/Sync if `T` is,
check) and implementing Send/Sync if `T` is, we get the same results as using we get the same results as using `Unique<T>`:
`Unique<T>`:
```rust ```rust
use std::ptr::NonNull; use std::ptr::NonNull;
@ -49,7 +46,6 @@ pub struct Vec<T> {
ptr: NonNull<T>, ptr: NonNull<T>,
cap: usize, cap: usize,
len: usize, len: usize,
_marker: PhantomData<T>,
} }
unsafe impl<T: Send> Send for Vec<T> {} unsafe impl<T: Send> Send for Vec<T> {}
@ -58,4 +54,5 @@ unsafe impl<T: Sync> Sync for Vec<T> {}
``` ```
[ownership]: ../ownership.html [ownership]: ../ownership.html
[phantom-data]: ../phantom-data.md
[NonNull]: ../../std/ptr/struct.NonNull.html [NonNull]: ../../std/ptr/struct.NonNull.html

@ -13,7 +13,6 @@ allocating, growing, and freeing:
struct RawVec<T> { struct RawVec<T> {
ptr: NonNull<T>, ptr: NonNull<T>,
cap: usize, cap: usize,
_marker: PhantomData<T>,
} }
unsafe impl<T: Send> Send for RawVec<T> {} unsafe impl<T: Send> Send for RawVec<T> {}
@ -25,7 +24,6 @@ impl<T> RawVec<T> {
RawVec { RawVec {
ptr: NonNull::dangling(), ptr: NonNull::dangling(),
cap: 0, cap: 0,
_marker: PhantomData,
} }
} }

@ -33,14 +33,13 @@ method of `RawVec`.
```rust,ignore ```rust,ignore
impl<T> RawVec<T> { impl<T> RawVec<T> {
fn new() -> Self { fn new() -> Self {
// !0 is usize::MAX. This branch should be stripped at compile time. // This branch should be stripped at compile time.
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 }; let cap = if mem::size_of::<T>() == 0 { usize::MAX } else { 0 };
// `NonNull::dangling()` doubles as "unallocated" and "zero-sized allocation" // `NonNull::dangling()` doubles as "unallocated" and "zero-sized allocation"
RawVec { RawVec {
ptr: NonNull::dangling(), ptr: NonNull::dangling(),
cap: cap, cap: cap,
_marker: PhantomData,
} }
} }

Loading…
Cancel
Save