2015-01-08 7 views
6

Vorrei che un oggetto di grandi dimensioni dicesse Vec<Vec<MyStruct> da inizializzare con una funzione. Attualmente hoPosso restituire in modo efficiente l'oggetto in base al valore in Rust?

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

quando vorrei

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

In C++ spesso così ho sentito, implementa l'ottimizzazione valore di ritorno, se si è fortunati e hanno un buon compilatore. Possiamo disabilitare la copia qui e averla restituita fondamentalmente da un puntatore nascosto che viene passato alla funzione? Ed è RVO parte della lingua o un'ottimizzazione opzionale?

+0

[Questa discussione] (http://discuss.rust-lang.org/t/implementation-details/948/5) suggerisce che RVO si innesca per qualcosa di più grande di un puntatore. Ma c'è anche [questo problema aperto] (https://github.com/rust-lang/rust/issues/18363) riguardante NRVO. Quindi penso che dipenda esattamente da come si implementa 'initialize'. – Michael

risposta

12

Sì, con tutti i mezzi, si dovrebbe scrivere

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

(BTW, Vec non è grande - è a soli 3 interi puntatore di dimensioni, ma ancora)

Rust ha RVO, e questo è pubblicizzato nelle guide, ad esempio here. Puoi vederlo da solo.

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

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

Se si esegue questo programma on playpen con il tasto "asm", tra tutto il resto si poteva vedere questo:

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

Vec::new() stato inline, ma comunque si può vedere l'idea - l'indirizzo per la nuova istanza Vec viene passata alla funzione in %rdi e la funzione memorizza i campi Vec direttamente in questa memoria, evitando inutili copie attraverso lo stack. Ed è così che si chiama:

leaq (%rsp), %rdi 
    callq _ZN10initialize20h5d5903a85c1850a8eaaE 

Si può vedere che alla fine l'istanza Vec sarà messo direttamente nella memoria dello stack.

+0

IMO, LLVM IR indica il puntatore esterno in modo più chiaro. – huon

+0

Probabilmente, ma trovo LLVM IR molto più difficile dell'assembly per qualche motivo :( –

+2

Per questo abbiamo solo bisogno della firma: 'define interno fastcc void @initialize (%" struct.collections :: vec :: Vec <[i32]> [# 3] "* noalias nocapture sret dereferenceable (24)) unnamed_addr # 0'. LLVM IR è simile C per le dichiarazioni, così che la funzione restituisce' void' e prende un puntatore ('*') in un 'struct.collections :: vec :: Vec <[i32]> '. (Ho usato' # [no_mangle] 'per renderlo più chiaro.) – huon

Problemi correlati