2013-02-26 12 views
8

So che una variabile __block verrà spostata nell'heap dalla pila se è stato copiato un blocco di accesso. Ma il seguente codice di test mi mostra che la variabile __block viene spostata nell'heap prima della copia del blocco.Perché una variabile __block viene spostata nell'heap PRIMA che il blocco venga copiato?

Ovvero, le quattro uscite sono: stack => heap => heap => heap, che non è il risultato previsto: stack => stack => stack => heap.

Qualcuno potrebbe raddrizzarmi?

__block int x = 0; 
int *pointerToX = &x; 
//1. It's on the stack 
NSLog(@"x's location is on the stack: %p", &x); 
int (^block)() = ^{ 
    x += 1; 
    return x; 
}; 

//2. I think its stack, but it's heap 
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack 

block(); 
//3. I think its stack, but it's heap 
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack 

block = [block copy]; // The variable x will be moved to the heap 
//4. I think its stack, but it's heap 
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //heap 
+0

perché vi preoccupate per questo comunque? e cosa succede a '__block int x; int * ptr = & x; 'se la variabile viene spostata da una pila all'altra? –

+2

È un dettaglio di implementazione. Dovresti cercare di non pensare troppo a loro. –

+2

La registrazione della classe del blocco (sì, i blocchi sono oggetti) è anche utile per determinare dove è stata copiata ('__NSStackBlock__',' __NSMallocBlock__'). – CodaFi

risposta

3

Lasciatemi prefigurare dicendo: I blocchi sono strani.

Ora, quando si avvia, è stata dichiarata una variabile x e anche il prefisso è __block. Che diamine è __block comunque? Bene, per gli oggetti catturati nello scope lessicale del blocco, le variabili sono 'ed in modo da garantire che siano intorno quando il blocco viene eseguito. Ma per le variabili primitive, i blocchi proteggono i loro valori forzandoli a passare per il valore const anziché per riferimento. Prevedendo lo __block, hai dato al compilatore il dominio per spostare la tua variabile "magicamente" dallo stack all'heap quando il blocco è stato copiato. Per essere chiari, le variabili __block sono, infatti, allocate allo stack, ma vengono spostate nell'heap (malloc() 'd) quando il blocco viene copiato.

Ma che dire degli strani cambiamenti nella posizione di x? Bene, di nuovo a __block di nuovo. Poiché non stai usando un riferimento a xa x come una variabile normale, i blocchi usano un trucco (leggermente fastidioso): un blocco crea un puntatore a qualsiasi variabile __block e, se tale variabile è mutata, viene dereferenziata. Ta da! La tua variabile non si è spostata dallo stack all'heap, il blocco si limitava a dereferenziare il puntatore ad esso e lo spostava in memoria!

Quindi, davvero, sei confuso su dove e quando le tue variabili vengono spostate. Il tuo esempio sta registrando i valori corretti.

+0

"Ma per le variabili primitive, i blocchi proteggono i loro valori forzandoli a passare per valore const anziché per riferimento." Questo è vero per tutti i tipi. Le variabili non '_blocchi', indipendentemente dal tipo, vengono catturate dal valore quando viene creato il blocco. – newacct

2

L'output previsto si basa sul presupposto che il blocco non viene copiato fino al passaggio 3-4. Tuttavia, nulla nelle specifiche Blocks garantisce che sarebbe il caso.

Sì, il blocco verrà copiato al più tardi quando si chiama esplicitamente -copy su di esso. Ma perché non può essere copiato in precedenza? Non è mai errato per copiare un blocco in precedenza. Pertanto, quando un blocco esattamente viene copiato non è definito, e non si deve dipendere da esso.

Alcune versioni recenti del compilatore sotto ARC possono essere conservative e copiare un blocco subito dopo la sua creazione. Non c'è niente di sbagliato in questo. Di nuovo, se lo fa, sarebbe un dettaglio di implementazione, e altri compilatori o versioni future potrebbero fare qualcosa di diverso.

0

ho fatto una stessa domanda a In Objective-C with ARC, what does compiler do when I define a block?

caso si esegue il codice in ARC

In ARC,

variabili a blocchi di conservazione di tipo di oggetto proprietario vengono spostati dallo stack inizializzando la copia heap con il risultato dello spostamento dalla copia dello stack .

in http://clang.llvm.org/docs/AutomaticReferenceCounting.html#blocks

+0

Quando si citano altri post, assicurarsi di includere la citazione corretta. –

+0

Sì, è causato da ARC. – jcccn

Problemi correlati