2015-01-08 24 views
6

大きなオブジェクトをVec<Vec<MyStruct>という関数で初期化したいとします。私は、多くの場合、私は聞いたことがあるC++ではRustでオブジェクトを効率的に値で返すことはできますか?

fn initialize() -> Vec<Vec<MyStruct>> { ... } 

が好きなあなたは幸運であれば、戻り値の最適化を実現し、優れたコンパイラを持っているだろうというとき現在、私は

fn initialize(mydata : &mut Vec<Vec<MyStruct>>) { ... } 

を持っています。ここでコピーを無効にして、関数に渡される隠しポインタによって基本的に返すことはできますか? RVOは言語の一部か最適化オプションですか?

+0

[このディスカッション](http://discuss.rust-lang.org/t/implementation-details/948/5)は、RVOがポインタより大きなものをトリガすることを示唆しています。しかし、NRVOに関する[この未公開の問題](https://github.com/rust-lang/rust/issues/18363)もあります。ですから、私はそれが 'initialize'をどのように実装しているかによって決まると思います。 – Michael

答えて

12

はい、すべての手段によって、あなたは

fn initialize() -> Vec<Vec<MyStruct>> { ... } 

を書くべき(ところで、Vecはその大きさではありません - それは唯一の3ポインタサイズの整数だが、それでも)

錆がRVOがあり、この例えばhereのようにガイドに広告されています。あなたはそれを自分で見ることができます。

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

fn main() { 
    let v = initialize(); 
} 

あなたが他のすべての中で、「ASM」ボタンでこのプログラムon playpenを実行する場合は、この見ることができる:

_ZN10initialize20h5d5903a85c1850a8eaaE: 
    .cfi_startproc 
    movq $1, (%rdi) 
    movq $0, 16(%rdi) 
    movq $0, 8(%rdi) 
    movq %rdi, %rax 
    retq 

Vec::new()がインライン化されましたが、それにもかかわらず、あなたのアイデア見ることができる - のアドレスを新しいVecインスタンスが%rdiの関数に渡され、関数はVecフィールドをこのメモリに直接格納し、スタックを介した不要なコピーを回避します。そして、これは、それが呼ばれる方法です。

leaq (%rsp), %rdi 
    callq _ZN10initialize20h5d5903a85c1850a8eaaE 

あなたは最終的にVecインスタンスがスタックメモリに直接置かれることがわかります。

+0

IMO、LLVM IRはアウトポインタをより明確に示します。 – huon

+0

おそらく、私はLLVM IRが何らかの理由でアセンブリよりもはるかに難しいと感じるでしょう:( –

+2

これについては、単に署名が必要です: 'define internal fastcc void @initialize(%" struct.collections :: vec :: Vec <[i32]> [ LLVM IRは宣言に似ているので、関数は 'void'を返し、' struct.collections :: vec( ')'にポインタ( '*')をとります。 :: Vec <[i32]> '。(#[no_mangle]'を使ってより明確にしました) – huon

関連する問題