Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I efficiently return an object by value in Rust?

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?

like image 460
stevenkucera Avatar asked Jan 08 '15 07:01

stevenkucera


1 Answers

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.

like image 67
Vladimir Matveev Avatar answered Oct 04 '22 18:10

Vladimir Matveev