2011-01-31 12 views
28

Ho avuto l'impressione che in C#, gli elementi struct sono allocati nello stack e quindi scompaiono quando ritornano da un metodo in cui sono stati creati. Ma cosa succede se metto i valori struct in una lista e lo restituisco? Gli elementi sopravvivono. Le istanze di struct sono talvolta allocate nell'heap?Le strutture vengono sempre allocate o talvolta allocate?

internal struct Stru 
{ 
    public int i; 
} 

internal class StruTry 
{ 
    public List<Stru> Get(int max) 
    { 
    var l = new List<Stru>(); 
    for (int i = 0; i < max; i++) 
     l.Add(new Stru {i=i}); 

    return l; 
    } 
} 

codice di stampa 0, 1, 2

[Test] 
public void T() 
{ 
    var ll = new StruTry().Get(3); 
    foreach (var stru in ll) 
    Console.WriteLine("* "+ stru.i); 
} 

risposta

42

In primo luogo, leggere questo post di Eric Lippert su The Stack is an Implementation Detail. Seguilo con The Truth about Value Types. Come per la tua domanda specifica

Le istanze di struct sono talvolta allocate nell'heap?

Sì, a volte vengono allocati nello heap. Ci sono molti esempi di quando possono essere allocati nell'heap. Se sono in scatola, o se sono campi in una classe, o se sono elementi di una matrice, o se sono il valore di una variabile di tipo di valore che è stata chiusa, ecc.

Ma cosa succede se metto i valori struct in una lista e lo restituisco? Gli elementi sopravvivono.

Stai pensando a questo nel modo giusto, e questo è uno dei punti salienti su cui un tipo di valore potrebbe essere assegnato. Vedi il secondo post a cui ho fatto riferimento su The Truth About Value Types per maggiori dettagli. Ma tenere a mente The Stack è un dettaglio di implementazione in mente. La chiave d'asporto è che non hai davvero bisogno di preoccuparti di queste cose. Dovresti preoccuparti della differenza semantica tra tipi di valore e tipi di riferimento.

+3

Quest'ultimo punto riguarda solo "sto passando per valore o per riferimento" e non "è il mio oggetto in pila o l'heap" - è difficile per me perché principalmente programma in C++. Penso che ogni programmatore C/C++ pensi in termini di dove un oggetto vive. In C/C++ le strutture (e le classi in C++) possono vivere in entrambi i posti a seconda di come sono dichiarate. Sembra che la cosa principale per ogni programmatore C/C++ in C# sia di rompere questa abitudine e non pensare mai a dove un oggetto vive. –

+0

@jason Che ne dici di strutture generiche come struct sockaddr, come si può allocare lo stack senza conoscere la giusta dimensione (poiché questa struttura generica è per definizione più piccola della struttura IPv6 sockaddr_in6) – Bionix1441

+0

@jason Che cosa significa "se sono il valore di una variabile di tipo di valore che è stata chiusa su "? – Pingpong

12

Le strutture sono come ints. Se si dispone di un int locale, sarà in genere in pila, se si dispone di un elenco di ints, essi vengono memorizzati direttamente nell'array interno della lista, che si trova nell'heap. Le strutture si comportano allo stesso modo.

1

Tutti i tipi possono essere assegnati sull'heap. Oltre a ciò, heap/stack è un dettaglio di implementazione del CLR e non delle specifiche C#, quindi non dovresti mai fare affidamento su tali cose. Vedi here per un buon post sul blog su questo argomento.

1

Da quello che mi ricordo ...

La posizione dei tipi di valore dipende da dove sono dichiarate. Le variabili di metodo vengono allocate, memorizzate nello stack e rimosse dopo l'esecuzione del metodo nel frame dello stack. I tipi di valore dichiarati come parte di un tipo di riferimento sono memorizzati nell'heap all'interno della struttura del tipo di inclusione.

Fammi sapere se mi sbaglio!

+2

Se per "variabile di metodo" si intende la variabile locale, la propria affermazione non è completamente accurata. Ad esempio, se la variabile locale viene chiusa in un'espressione lambda, verrà issata come membro della classe definita dalla compilazione e verrà allocata nell'heap esattamente come gli altri campi di una classe. La chiave è che tale variabile locale potrebbe vivere più a lungo del metodo di definizione e quindi deve essere allocata lontano dallo stack. – jason

5

Ma cosa succede se metto i valori di struct in un elenco e lo restituisco? Gli elementi sopravvivono.

Tecnicamente i valori aggiunti alla "Lista" non sono gli stessi valori, sono copie basate sul valore. Se, ad esempio, si modifica l'originale, tali modifiche non verranno trasferite alla copia nell'elenco. Inoltre, "Elenco" restituisce una copia del valore all'indice indicato.Ciò significa che se la struttura è modificabile e si modifica il valore restituito da "Elenco", il valore di List<t> rimarrà invariato. Questo non è il caso degli array, dato che l'indice dell'array fornisce l'accesso alla variabile attuale.

1

Una posizione di memoria (variabile, campo, parametro, slot di matrice, ecc.) Di tipo struct contiene i campi pubblici e privati ​​della struct al suo interno. Se la posizione di archiviazione è nello stack, i campi della struct saranno in pila. Se si trova all'interno di un'altra classe o struttura, i campi della struct verranno memorizzati come parte dell'altra classe o istanza di struct.

Una posizione di tipo classe di memoria detiene un riferimento ad un oggetto completo classe che è sempre o (1) memorizzato posto completamente separato dal magazzino possesso di un riferimento, o (2) oggetto classe di cui quella posizione di memoria è un campo.

Problemi correlati