-
Notifications
You must be signed in to change notification settings - Fork 11
Description
When you create a vector like
let mut a = vec![vec![42; 45]; 498];
The allocations happen in this order:
- the last inner vec
- the outer vec
- the rest of the inner vecs, in order of index
This is because the vec!
macro expands like so:
let a = ::alloc::vec::from_elem(::alloc::vec::from_elem(42, 45), 498);
One inner vector gets allocated, then the outer vector gets allocated (using with_capacity()
). Then the initial inner vector gets repeatedly cloned, until the outer vector is filled.
By why does the first inner vector end up last? This is down to an implementation detail in extend_with
, which is what ultimately gets called:
// Write all elements except the last one
for _ in 1..n {
ptr::write(ptr, value.clone());
ptr = ptr.add(1);
// Increment the length in every step in case clone() panics
local_len.increment_len(1);
}
if n > 0 {
// We can write the last element directly without cloning needlessly
ptr::write(ptr, value);
local_len.increment_len(1);
}
This is documented nowhere and extend_with
isn't even part of the public API. Nevertheless, it is possible to observe this behaviour by creating a broken implementation of Clone
like so:
#[derive(Debug)]
struct Dumb(i32);
// broken implementation of clone
impl Clone for Dumb {
fn clone(&self) -> Self {
Dumb(0)
}
}
fn main() {
let a = vec![Dumb(439); 5];
dbg!(a);
}
Which reveals that Dumb(439)
is in fact sitting at the back.
This is so obscure and stupid that I think it would be perfect for this quiz.
EDIT: An easier way to observe this would be to simply run the following:
fn main() {
let vecs = vec![Vec::<u8>::with_capacity(10); 5];
for v in vecs {
println!("{}", v.capacity());
}
}
For which the output is:
0
0
0
0
10