I would like to initialize a large object with a function. Currently I have:
fn initialize(mydata: &mut Vec<Vec<MyStruct>>) { /* ... */ }
I would prefer to have:
fn initialize() -> Vec<Vec<MyStruct>> { /* ... */ }
I've heard that C++ often implements return value optimization (RVO), if you are lucky and have a good compiler. Can we disable copying here and have it returned by a hidden pointer that is passed into the function? Is RVO part of the language or an optional optimization?
Yes, by all means, you should write
fn initialize() -> Vec<Vec<MyStruct>> { ... }
(By the way, a Vec
is not that large - it's only 3 pointer-sized integers)
Rust has RVO, and this is advertised in guides. You can see it yourself with this code:
#[inline(never)]
fn initialize() -> Vec<i32> {
Vec::new()
}
fn main() {
let v = initialize();
}
If you compile this program in release mode on the playground, outputting assembly, among everything else you will see this:
playground::initialize:
movq $4, (%rdi)
xorps %xmm0, %xmm0
movups %xmm0, 8(%rdi)
retq
Vec::new()
was inlined, but you can see the idea - the address for the fresh Vec
instance is passed into the function in %rdi
, and the function stores Vec
fields directly into this memory, avoiding unnecessary copying through the stack. This is how it is called:
playground::main:
subq $24, %rsp
movq %rsp, %rdi
callq playground::initialize
You can see that eventually the Vec
instance will be put directly into the stack memory.