Rustonomicon: Fix bug in implementation of Vec::drain()

In the last code snippet on the following page there is a bug in the
implementation of Vec::drain().

https://doc.rust-lang.org/nightly/nomicon/vec-drain.html

```rust
pub fn drain(&mut self) -> Drain<T> {
    // Oops, setting it to 0 while we still need the old value!
    self.len = 0;

    unsafe {
        Drain {
            // len is used to create a &[T] from &self here,
            // so we end up always creating an empty slice.
            iter: RawValIter::new(&self),
            vec: PhantomData,
        }
    }
}
```

A simple test to verify that Drain is broken can be found here:
https://play.rust-lang.org/?gist=30f579565e4bbf4836ce&version=nightly

And here's one with a fixed implementation:
https://play.rust-lang.org/?gist=2ec0c1a6dcf5defd7a53&version=nightly
pull/10/head
Jørn Lode 9 years ago committed by Manish Goregaokar
parent 00fdb72cc8
commit 2574990a3f

@ -129,14 +129,16 @@ impl<'a, T> Drop for Drain<'a, T> {
impl<T> Vec<T> { impl<T> Vec<T> {
pub fn drain(&mut self) -> Drain<T> { pub fn drain(&mut self) -> Drain<T> {
// this is a mem::forget safety thing. If Drain is forgotten, we just unsafe {
// leak the whole Vec's contents. Also we need to do this eventually let iter = RawValIter::new(&self);
// this is a mem::forget safety thing. If this is forgotten, we just
// leak the whole Vec's contents. Also we need to do this *eventually*
// anyway, so why not do it now? // anyway, so why not do it now?
self.len = 0; self.len = 0;
unsafe {
Drain { Drain {
iter: RawValIter::new(&self), iter: iter,
vec: PhantomData, vec: PhantomData,
} }
} }

@ -155,13 +155,16 @@ impl<T> Vec<T> {
} }
pub fn drain(&mut self) -> Drain<T> { pub fn drain(&mut self) -> Drain<T> {
unsafe {
let iter = RawValIter::new(&self);
// this is a mem::forget safety thing. If this is forgotten, we just // this is a mem::forget safety thing. If this is forgotten, we just
// leak the whole Vec's contents. Also we need to do this *eventually* // leak the whole Vec's contents. Also we need to do this *eventually*
// anyway, so why not do it now? // anyway, so why not do it now?
self.len = 0; self.len = 0;
unsafe {
Drain { Drain {
iter: RawValIter::new(&self), iter: iter,
vec: PhantomData, vec: PhantomData,
} }
} }

Loading…
Cancel
Save