Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I copy a vector to another location and reuse the existing allocated memory?

In C++, to copy the contents of a vector to another vector we use the assignment operator dest = src. However, in Rust src would be moved into dest and no longer usable.

I know the simplest answer is to do dest = src.clone() (for the sake of this question we'll assume T in Vec<T> is Clone). However - if I'm understanding correctly - this creates a brand new third vector with the copied contents of src and moves it into dest, throwing away dest's dynamically allocated array. If this is correct, it's a completely unnecessary dynamic allocation when we could have just copied the content directly into dest (assuming it had sufficient capacity).

Below is a function I've made that does exactly what I would like to do: empty out the dest vector and copy the elements of src to it.

// copy contents of src to dest without just cloning src
fn copy_content<T: Clone>(dest: &mut Vec<T>, src: &Vec<T>) {
    dest.clear();
    if dest.capacity() < src.len() {
        dest.reserve(src.len());
    }
    for x in src {
        dest.push(x.clone());
    }
}

Is there a way to do this with builtin or standard library utilities? Is the dest = src.clone() optimized by the compiler to do this anyway?

I know that if T has dynamic resources then the extra allocation from src.clone() isn't a big deal, but if T is e.g. i32 or any other Copy type then it forces an allocation where none are necessary.

like image 465
Cruz Jean Avatar asked Jan 05 '20 22:01

Cruz Jean


People also ask

How do you copy vector vectors?

You just use its copy constructor or assignment operator: std::vector<std::vector<int> > vec; std::vector<std::vector<int> > copy_of_vec = vec; Yes, it's really that simple once you get rid of all the pointers.

What is a vector copy?

Copy enables you to: define a vector of operands, copy the values or bit status of each operand within that vector, write those values or status into a corresponding vector of operands of the same length.


1 Answers

Did you ever look at the definition of Clone? It has the well known clone method but also a useful but often forgotten clone_from method:

pub trait Clone : Sized {
    fn clone(&self) -> Self;
    fn clone_from(&mut self, source: &Self) {
        *self = source.clone()
    }
}

To quote the doc:

Performs copy-assignment from source.

a.clone_from(&b) is equivalent to a = b.clone() in functionality, but can be overridden to reuse the resources of a to avoid unnecessary allocations.

Of course a type such as Vec does not use the provided-by-default clone_from and defines its own in a more efficient way, similar to what you would get in C++ from writing dest = src:

fn clone_from(&mut self, other: &Vec<T>) {
    other.as_slice().clone_into(self);
}

with [T]::clone_into being defined as:

fn clone_into(&self, target: &mut Vec<T>) {
    // drop anything in target that will not be overwritten
    target.truncate(self.len());
    let len = target.len();

    // reuse the contained values' allocations/resources.
    target.clone_from_slice(&self[..len]);

    // target.len <= self.len due to the truncate above, so the
    // slice here is always in-bounds.
    target.extend_from_slice(&self[len..]);
}
like image 116
mcarton Avatar answered Oct 18 '22 21:10

mcarton