Search code examples
rustvectormemory-managementdeque

How is memory handled when calling the `extend` and `drain` methods from Vec and VecDeque?


In Rust, do the methods extend and drain from Vec and VecDeque copy the contents of the items, or are the items moved in like in a list?

Consider that reserve reserve has been called prior, and that the Vec/VecDeque already have space for the elements.

Edit: For clarification, what happens, at memory level, with the following code? Are the contents copied from Vec to VecDeque, or is there simply a change in pointers like removing/inserting in a linked list?

let mut a: Vec<i32> = (0..10).collect();
let mut b: VecDeque<i32> = VecDeque::new();
b.reserve(10);

b.extend(a.drain(..));

Solution

  • The data of a and b are on fixed locations in memory. Because b already has enough capacity, a reallocation of b won't happen.

    The data itself, though, will be memcopied from a to b, and a will be marked empty afterwards.


    To demonstrate, here is a little program that shows the inner state of a Vec during such a process:

    use std::fmt::Debug;
    
    macro_rules! dbg_vec {
        ($v: ident) => {
            dbg_vec_impl(stringify!($v), &$v);
        };
    }
    
    fn dbg_vec_impl<T: Debug>(name: &str, v: &Vec<T>) {
        println!(
            "Vec '{}': ({:p}, {}, {})",
            name,
            v.as_ptr(),
            v.len(),
            v.capacity()
        );
        println!("    Real content:   {:?}", v);
        unsafe {
            println!(
                "    Memory content: {:?}",
                std::slice::from_raw_parts(v.as_ptr(), v.capacity())
            )
        };
    }
    
    fn main() {
        let mut a: Vec<i32> = (0..10).collect();
        let mut b: Vec<i32> = Vec::new();
        dbg_vec!(a);
        dbg_vec!(b);
    
        b.reserve(10);
        println!("\nb.reserve(10);\n");
    
        dbg_vec!(a);
        dbg_vec!(b);
    
        b.extend(a.drain(..));
        println!("\nb.extend(a.drain(..))\n");
    
        dbg_vec!(a);
        dbg_vec!(b);
    
        a.shrink_to_fit();
        b.shrink_to_fit();
        println!("\nshrink_to_fit()\n");
    
        dbg_vec!(a);
        dbg_vec!(b);
    }
    
    Vec 'a': (0x1e932d5deb0, 10, 10)
        Real content:   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    Vec 'b': (0x4, 0, 0)
        Real content:   []
        Memory content: []
    
    b.reserve(10);
    
    Vec 'a': (0x1e932d5deb0, 10, 10)
        Real content:   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    Vec 'b': (0x1e932d5dd60, 0, 10)
        Real content:   []
        Memory content: [5439557, 5505099, 5242959, 7667773, 6553710, 6684773, 7209065, 6553701, 5177344, 3997779]
    
    b.extend(a.drain(..))
    
    Vec 'a': (0x1e932d5deb0, 0, 10)
        Real content:   []
        Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    Vec 'b': (0x1e932d5dd60, 10, 10)
        Real content:   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    shrink_to_fit()
    
    Vec 'a': (0x4, 0, 0)
        Real content:   []
        Memory content: []
    Vec 'b': (0x1e932d5dd60, 10, 10)
        Real content:   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        Memory content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]