3 ms·
I really appreciate Rust's copy/clone semantics when reading this. The "hopefully" is so worrying. Production code in Rust is littered with imperformant `.clon
by rtpg 2y ago
I really appreciate Rust's copy/clone semantics when reading this. The "hopefully" is so worrying.
Production code in Rust is littered with imperformant `.clone()`s but at least I can see where they're happening to ponder a better way.
- Arnavion 2y agoActually, Rust would also really like an `emplace_back`, because it does have the issue that `.push_back(Widget::new(foo, bar, baz))` can end up creating a Widget local in the caller and then moving it into the Vec allocation. It doesn't happen as much with optimizations enabled, but it does happen in debug builds. You might say "Big deal, it's just a tiny loss of performance to create a value and then copy it into its final place. Unlike C++ this is guaranteed to only do a copy of bytes, no complex code like a copy ctor. Who cares, especially if it's only noticeable in debug builds?" But it's not just a problem of performance. If it's `Box::new([0_u8; 10 * 1024 * 1024])`, then that 10 MiB array created in the caller's stack can end up blowing the caller's stack. Rust did actually try to add emplace style APIs and a dedicated operator. It would've looked like `vec.place_back() <- Widget::new();` and it would've guaranteed that the generated code did not create a copy in the caller frame. It was never stabilized and instead eventually removed, because it was still not reliable enough to provide that guarantee after all. https://github.com/rust-lang/rfcs/blob/master/text/1228-placement-left-arrow.md https://github.com/rust-lang/rfcs/blob/master/text/1228-plac... https://doc.rust-lang.org/1.26.0/std/vec/struct.Vec.html#method.place_back https://doc.rust-lang.org/1.26.0/std/vec/struct.Vec.html#met... https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911 https://github.com/rust-lang/rust/issues/27779#issuecomment-...
- tialaramex 2y agoThe Box::new_zeroed family lets us sidestep this. I thought it was stabilised, but looks like not yet Box::<u8>::new_zeroed_slice(10 * 1024 * 1024) says we want 10MiB of zero bytes as a MaybeUninit inside a box, we can then (since these are just bytes in our example) assume_init() since that's valid for our type although in the real world probably we'd actually store some actual data in the memory we've allocated - but it doesn't go on the stack. If we're overwriting it all anyway there's also an adjacent set of uninit functions to skip the zero step, although of course the OS might be zeroing the page anyway.
- Arnavion 2y agoRight, in the absence of placement-exprs, the alternatives are based around MaybeUninit. Box::new_zeroed() for the "boxed zero array" case, Box::new_uninit() + MaybeUninit::write() + Box::assume_init() for the "boxed arbitrary large value case", Vec::reserve() + Vec::spare_capacity_mut() + MaybeUninit::write() + Vec::set_len() for the "append to Vec" case, etc.