我可以在Rust中按值有效地返回一个对象吗?

ste*_*era 7 optimization rust return-value-optimization

我想用函数初始化一个大对象.目前我有:

fn initialize(mydata: &mut Vec<Vec<MyStruct>>) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

我更愿意:

fn initialize() -> Vec<Vec<MyStruct>> { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

我听说C++经常实现返回值优化(RVO),如果你很幸运并拥有一个好的编译器.我们可以在这里禁用复制并通过传递给函数的隐藏指针返回吗?RVO是语言的一部分还是可选的优化?

Vla*_*eev 13

是的,无论如何,你应该写

fn initialize() -> Vec<Vec<MyStruct>> { ... }
Run Code Online (Sandbox Code Playgroud)

(顺便说一句,a Vec不是那么大 - 它只有3个指针大小的整数)

Rust有RVO,这在指南中做广告.您可以使用以下代码自行查看:

#[inline(never)]
fn initialize() -> Vec<i32> {
    Vec::new()
}

fn main() {
    let v = initialize();
}
Run Code Online (Sandbox Code Playgroud)

如果你在操场上以发布模式编译这个程序,输出程序集,在其他所有内容中你会看到:

playground::initialize:
    movq    $4, (%rdi)
    xorps   %xmm0, %xmm0
    movups  %xmm0, 8(%rdi)
    retq
Run Code Online (Sandbox Code Playgroud)

Vec::new()内联,但您可以看到这个想法 - 新鲜Vec实例的地址被传递到函数中%rdi,并且函数将Vec字段直接存储到此内存中,从而避免通过堆栈进行不必要的复制.这就是它的名称:

playground::main:
    subq    $24, %rsp
    movq    %rsp, %rdi
    callq   playground::initialize
Run Code Online (Sandbox Code Playgroud)

您可以看到最终Vec实例将直接放入堆栈内存中.

  • 为此我们只需要签名:`define internal fastcc void @initialize(%"struct.collections :: vec :: Vec <[i32]> [#3]"*noalias nocapture sret dereferenceable(24))unnamed_addr#0` .LLVM IR与声明类似,因此该函数返回`void`并将指针(`*`)带到`struct.collections :: vec :: Vec <[i32]>`.(我使用`#[no_mangle]`来使它更清晰.) (2认同)