web-dev-qa-db-fra.com

Les structures sont-elles toujours allouées en pile ou parfois en tas?

J'avais l'impression qu'en C #, les éléments struct sont alloués sur la pile et disparaissent donc au retour d'une méthode dans laquelle ils ont été créés. Mais que se passe-t-il si je place les valeurs de structure dans une liste et que je les renvoie? Les éléments survivent. Les instances de struct sont-elles parfois allouées sur le tas?

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;
  }
}

impression de code 0, 1, 2

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

Tout d'abord, lisez ce post d'Eric Lippert sur La pile est un détail d'implémentation . Suivez-le avec La vérité sur les types de valeur . Quant à votre question spécifique

Les instances de struct sont-elles parfois allouées sur le tas?

Oui, ils sont parfois alloués sur le tas. Il existe de nombreux exemples de cas où ils pourraient être alloués sur le tas. S'ils sont encadrés, ou s'ils sont des champs d'une classe, ou s'ils sont des éléments d'un tableau, ou s'ils sont la valeur d'une variable de type valeur qui a été fermée, etc.

Mais que se passe-t-il si je place les valeurs de structure dans une liste et que je les renvoie? Les éléments survivent.

Vous pensez à cela de la bonne façon, et c'est l'un des points saillants sur où un type de valeur peut être alloué. Voir le deuxième article auquel j'ai fait référence dans The Truth About Value Types pour plus de détails. Mais gardez à l'esprit The Stack est un détail d'implémentation à l'esprit. Le point clé à retenir est que vous n'avez vraiment pas besoin de vous préoccuper de ce genre de choses. Vous devez vous préoccuper de la différence sémantique entre les types de valeur et les types de référence.

59
jason

Les structures sont comme ints. Si vous avez un int local, il sera généralement sur la pile, si vous avez une liste de ints, ils sont stockés directement dans le tableau interne de la liste, qui se trouve sur le tas. Les structures se comportent de la même manière.

18
Marcelo Cantos

Mais que se passe-t-il si je place les valeurs de structure dans une liste et que je les renvoie? Les éléments survivent.

Techniquement, les valeurs ajoutées à la "liste" ne sont pas les mêmes valeurs, ce sont des copies basées sur des valeurs. Si, par exemple, vous modifiez l'original, ces modifications ne seront pas apportées à la copie dans la liste. De plus, 'List' renvoie une copie de la valeur à l'index indiqué. Cela signifie que si la structure est mutable et que vous modifiez la valeur renvoyée par la 'Liste', alors la valeur dans le List<t> restera inchangé. Ce n'est pas le cas avec les tableaux, car l'index du tableau donne accès à la variable réelle.

5
Trisped

Tous les types peuvent parfois être alloués sur le tas. En plus de cela, heap/stack est un détail d'implémentation du CLR et non dans la spécification C #, donc vous ne devriez jamais vous fier à de telles choses. Voir ici pour un bon article de blog sur ce sujet.

2
fearofawhackplanet

D'après ce dont je me souviens ...

L'emplacement des types de valeur dépend de l'endroit où ils sont déclarés. Les variables de méthode sont allouées, stockées sur la pile et supprimées après l'exécution de la méthode dans le cadre de pile. Les types de valeurs déclarés dans le cadre d'un type de référence sont stockés sur le tas dans la structure du type englobant.

Faites-moi savoir si je me trompe!

1
Matthew Abbott

Un emplacement de stockage (variable, champ, paramètre, emplacement de tableau, etc.) de type struct contient les champs publics et privés de la structure. Si cet emplacement de stockage est sur la pile, les champs de la structure seront sur la pile. S'il se trouve dans une autre classe ou structure, les champs de la structure seront stockés dans le cadre de cette autre instance de classe ou de structure.

Un emplacement de stockage de type classe contient un référence à un objet de classe complet qui est toujours soit (1) stocké dans un endroit complètement séparé de l'emplacement de stockage contenant une référence, soit (2) le objet de classe dont cet emplacement de stockage est un champ.

1
supercat