web-dev-qa-db-ja.com

構造体は常にスタック割り当てですか、それともヒープ割り当てですか?

C#では、構造体要素はスタックに割り当てられているため、それらが作成されたメソッドから戻ると消えます。しかし、構造体値をリストに入れてそれを返すとどうなりますか?要素は存続します。 構造体インスタンスがヒープに時々割り当てられていますか?

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

コード印刷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

まず、この記事をEric Lippertの スタックは実装の詳細 から読んでください。 値の型についての真実 を続けます。あなたの特定の質問について

構造体インスタンスがヒープに割り当てられることがありますか?

はい、それらは時々ヒープに割り当てられます。それらがヒープにいつ割り当てられるかについての例はたくさんあります。ボックス化されている場合、クラス内のフィールドである場合、配列の要素である場合、またはクローズされた値型の変数の値である場合など。

しかし、構造体値をリストに入れてそれを返すとどうなりますか?要素は存続します。

あなたはこれを正しい方法で考えています、そしてこれは値の型が割り当てられるかもしれない場所の際立ったポイントの一つです。詳細については、値の型についての真実について言及した2番目の投稿を参照してください。ただし、スタックは実装の詳細であることを覚えておいてください。重要なポイントは、このことに気を使う必要がないということです。値タイプと参照タイプのセマンティックの違いに注意する必要があります。

59
jason

構造体はintsのようなものです。ローカルintがある場合、それは通常スタック上にあります。intsのリストがある場合、それらはヒープのリストの内部配列に直接格納されます。構造体は同じように動作します。

18
Marcelo Cantos

しかし、構造体値をリストに入れてそれを返すとどうなりますか?要素は存続します。

技術的には、「リスト」に追加される値は同じ値ではなく、値に基づくコピーです。たとえば、オリジナルを変更した場合、それらの変更はリストのコピーには反映されません。また、「リスト」は、指定されたインデックスにある値のコピーを返します。これは、構造体が変更可能で、「リスト」から返された値を変更した場合、List<t>は変更されません。配列インデックスは実際の変数へのアクセスを提供するため、これは配列の場合とは異なります。

5
Trisped

すべてのタイプがヒープに割り当てられることがあります。それに加えて、ヒープ/スタックはCLRの実装の詳細であり、C#仕様にはありません。そのため、そのようなものに依存することはできません。この件に関する優れたブログ投稿については こちら を参照してください。

2

私が覚えていることから...

値型の場所は、それらが宣言されている場所によって異なります。メソッド変数は割り当てられ、スタックに格納され、スタックフレームでのメソッドの実行後に削除されます。参照型の一部として宣言された値型は、囲んでいる型の構造内のヒープに格納されます。

私が間違っているかどうか教えてください!

1
Matthew Abbott

構造体型の格納場所(変数、フィールド、パラメーター、配列スロットなど)は、その中に構造体のパブリックフィールドとプライベートフィールドを保持します。その格納場所がスタック上にある場合、構造体のフィールドはスタック上にあります。別のクラスまたは構造体内にある場合、構造体のフィールドは、他のクラスまたは構造体インスタンスの一部として保存されます。

クラスタイプの保存場所は、常に(1)参照を保持する保存場所とは完全に別の場所に保存される完全なクラスオブジェクトへの参照を保持します。 、または(2)theその保存場所がフィールドであるクラスオブジェクト。

1
supercat