2015-07-19 6 views
6

Stavo cercando di capire come si comportano le strutture quando vengono restituite dai metodi. C'è una sezione nella sezione nightly della "Ruggine Book" Detto questo, se si è utilizzato la sintassi ...I valori nella posizione di ritorno vengono sempre assegnati nel frame dello stack dei genitori o nella casella di ricezione?

let x = box i_return_a_struct(); 

.. che non ci sarebbe stata una copia, quindi non v'è alcuna necessità di restituire un puntatore. Ma quando ho iniziato a giocare con esso, sembra che lo box non sia necessario, a meno che non sia necessario che il valore esista nell'heap.

#[derive(Debug)] 
struct Dummy { 
    data: i64, 
} 

impl Drop for Dummy { 
    fn drop(&mut self) { 
     println!("{:?} is going out of scope", self as *const Dummy); 
    } 
} 

fn make_dummy(i: i64) -> Dummy { 
    Dummy { data: i } 
} 

fn main() { 
    { 
     let i = 15i32; 
     println!("{:?} is a variable on the stack frame", &i as *const i32); 

     let dummy1 = make_dummy(1); 
     println!("{:?} was returned and is being used", &dummy1 as *const Dummy); 
     let dummy2 = make_dummy(2); 
     println!("{:?} was returned and is being used", &dummy2 as *const Dummy); 

     let dummy3 = Box::new(make_dummy(3)); 
     println!("{:?} box was returned and is being used", &(*dummy3) as *const Dummy); 
     let dummy4 = Box::new(make_dummy(4)); 
     println!("{:?} box was returned and is being used", &(*dummy4) as *const Dummy); 
    } 
    println!("Leaving main"); 
} 

uscita:

0x23fb94 is a variable on the stack frame 
0x23faf8 was returned and is being used 
0x23fa50 was returned and is being used 
0x2825030 box was returned and is being used 
0x2825040 box was returned and is being used 
0x2825040 is going out of scope 
0x2825030 is going out of scope 
0x23fa50 is going out of scope 
0x23faf8 is going out of scope 
Leaving main 

fare valori/le strutture in posizione di ritorno sempre vengono assegnati nei genitori pila telaio o la ricezione di scatola?

MODIFICA: PS - c'è qualche indicazione nei documenti per quanto riguarda quando si verificherà l'elisione della copia in generale?

EDIT: Oltre la soluzione accettata, la seguente Q + A era illuminante: What are move semantics exactly? Chiarito molti punti per me.

risposta

2

Forse non mi è chiaro cosa non capisci. Penso che tu capisca, ma forse non lo sai ancora: D

Normalmente, il valore di ritorno di una funzione (make_dummy per esempio) viene inserito nello stack. Supponiamo ora di volere invece l'oggetto nell'heap. Con la nuova sintassi della casella, il compilatore può eseguire qualche ottimizzazione se si desidera che l'oggetto si trovi nell'heap.

Ora prendiamo l'esempio dal libro.

let y: Box<Dummy> = box make_dummy(some_dummy); 

Si potrebbe pensare che nell'esempio sopra si verifica quanto segue:

  1. il valore restituito da make_dummy viene scritto nello stack (come normalmente)
  2. una scatola viene allocato a contenere un Dummy oggetto
  3. il valore Dummy nella pila viene copiato nel puntatore della memoria dall'oggetto casella.

Con il vecchio meccanismo Box::new questo è esattamente ciò che accadrebbe. Invece, grazie alla sintassi casella sperimentale, questo è successo:

  1. A rigore assegnato
  2. Il puntatore a tale casella viene passato in qualche modo alla funzione make_dummy (con qualche magia compilatore), quindi il ritorno valore viene scritto direttamente alla memoria boxed [non ci sono copie extra che coinvolgono lo stack]

spero che sia più chiaro ora.

+0

Non c'è magia, la copia ellis è comune, si verifica già in molti compilatori C e C++. Questo è il motivo per cui ho collegato un gestore di Drop al mio oggetto, come mi aspetterei di vederlo scoppiare 2 volte per ogni chiamata se si verificava una copia.A meno che non mi sbagli, copia elision succede sempre nell'esempio nel mio post. –

+0

Voglio solo chiarire: 'Box :: new()' non è la sintassi "vecchia". In realtà è una funzione aggiunta per rendere possibile la creazione di un 'Box' su stable mentre la sintassi' box' è configurata. Se/quando 'box' viene stabilizzato,' Box :: new() 'probabilmente andrà via, o rimarrà semplicemente come un altro modo per ottenere un' Box'. –

+0

@RichHenry Se si verificava una copia, il compilatore si sarebbe lamentato del fatto che 'Dummy' non implementasse la caratteristica' Copia '. In caso di 'Box :: new (make_dummy (3))' il valore viene spostato (nel senso di trasferimento di proprietà) nella casella non copiata, quindi non si vedono i registri di drop aggiuntivi. Inoltre, 'Box :: new' è semplicemente una funzione che il compilatore non è in grado di ottimizzare il modo in cui ho descritto sopra, quindi ci sono ancora tutti gli elementi in movimento dallo stack allo heap. – eulerdisk

Problemi correlati