2

I want to copy (not move) a very big value from a box into a vec. The normal way of doing this (dereferencing the box) means the value is copied onto the stack temporarily, which blows it. Here's an example and a Playground link where it can be reproduced.

fn main() {
    let big_value = Box::new([0u8; 8 * 1024 * 1024]);
    let mut vec = Vec::new();
    vec.push(*big_value);
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5998cff185dc209e7a1e676d41850ff4

Since both the Box and the Vec are on the heap, it should be possible to do a copy without passing through the stack. What's the best solution here?

  • 3
    Not exactly a solution, but: Recent nightly versions of Rust should no longer suffer from this problem at all because LLVM is now smart enough to avoid the stack altogether. The playground successfully executes on nightly. – user2722968 May 01 '21 at 14:59
  • 2
    Isn't there a problem with the first line `Box::new([0u8; 8 * 1024 * 1024]);` too ? – Denys Séguret May 01 '21 at 15:00
  • no there is not (without unsafe), the correct solution is to avoid this, but as other said this is optimized out on nightly – Stargateur May 01 '21 at 15:03
  • 1
    Good to know. Looks like you need the release flag as well though - I'm going to hold out for another solution, because I'd like to continue using debug builds. – Jack Britton May 01 '21 at 15:15
  • 3
    Is there a reason you cannot use `big_value.into_vec()`? – Stephen Chung May 01 '21 at 15:29
  • https://stackoverflow.com/questions/35751927/how-to-convert-a-boxed-array-into-a-vec-in-rust – Stephen Chung May 01 '21 at 15:31
  • 4
    Please clarify: do you want the resulting `Vec` to be a `Vec<[u8; 8388608]>` of length 1, or a `Vec` of length 8388608? – trent May 01 '21 at 15:43
  • Like it says in the example - a `Vec` of length 1. – Jack Britton May 02 '21 at 00:30

1 Answers1

3

See this answer on a Reddit post I made: https://old.reddit.com/r/rust/comments/n2jasd/question_copy_big_value_from_box_into_vec_without/gwmrcxp/

You can do this with vec.extend_from_slice(std::slice_from_ref(&big_value));. This performs no allocations, and just copies the big_value from the heap into a new slot in the vec.