Garbage Collection

塵も積もれば山

目次

Blog 利用状況

ニュース

コミケで受けていた通販をすべて発送しました。詳しくはこちらの記事にて
C++とかC#とか数学ネタを投下していく予定です。
それ以外の日々の四方山話を綴った日記はこちら

書庫

日記カテゴリ

[C#]構造を蒐集する程度の能力

以下のプログラムをコンパイルして実行した結果、どうなるでしょう。

struct Position {
  public int x, y;
  public void Print() {
    Console.WriteLine(x.ToString() + "," + y.ToString());
  }
  public void swap() {
    int tmp = x;
    x = y;
    y = tmp;
  }
  public Position(int x, int y) {
    this.x = x;
    this.y = y;
  }
}
static void Main(string[] args) {
  var poslist = new List<Position>();
  poslist.Add(new Position(100, 200));
  poslist[0].Print();
  poslist[0].x += 300;
  poslist[0].Print();
}

なんと、コンパイルできません。
"エラー CS1612: 変数ではないため、'System.Collections.Generic.List<strlist.Program.Position>.this[int]' の戻り値を変更できません。"
こんなエラーが出るんですね。

では、このように関数の内部で値を変更してはどうでしょう。

static void Main(string[] args) {
  /* Positionの定義は上のソースと同じ */
  var poslist = new List<Position>();
  poslist.Add(new Position(100, 200));
  poslist[0].Print();
  poslist[0].swap();
  poslist[0].Print();
}

今度はコンパイルはできますが、予想通りswap()での交換は行われていません。

問題はposlist[0]の部分ですね。
上で出たエラーから推測すると、poslist[0]はposlist[0]ではありません。
poslist[0]の内容がコピーされたものが帰ってきているわけです。

Listに入れているものがclassであれば、実体を指し示す位置なので
コピーされたものであっても問題がありません。
しかし、今回はstructですので、コピーされたものを更新してしまい、
実際のposlist[0]の中身はまったく更新されないわけですね。

poslist[0].xとかやると、それ更新しても意味ないよって事でしょう。

ということで、結論です。

  • struct と Collections は相性が悪いので組み合わせないようにしましょう。
  • 追跡参照…追跡参照さえあればこんなことには…!!

#List<int>はまずいの?という話になりそうなんですが、その辺はもうちょっと調べて書きます。

投稿日時 : 2008年10月4日 4:42

Feedback

# [C#]整数も蒐集する程度の能力 2008/10/04 11:24 Garbage Collection

[C#]整数も蒐集する程度の能力

# re: [C#]構造を蒐集する程度の能力 2008/10/05 0:02 NyaRuRu

>追跡参照…追跡参照さえあればこんなことには…!!

この辺の事情についてはこちらをどうぞ.
http://d.hatena.ne.jp/NyaRuRu/20060616/p3

.NET 1.xの時代,Microsoft の verifier は ByRef returns を not verifiable と判定していたのですな.

# re: [C#]構造を蒐集する程度の能力 2008/10/05 0:09 よこけん

はじめまして

コレクションは直接関係ないですね。単なるクラスのプロパティでも同様の結果になりますよ。
そういった混乱の元となりますので、値型はイミュータブルにすべきです。
http://msdn.microsoft.com/ja-jp/library/ms229017.aspx

# re: [C#]構造を蒐集する程度の能力 2008/10/05 9:24 出水

>NyaRuRUさん
追跡参照を用意しない方針ってのは知ってます
ただ、本のタイトルからするとC#の方針じゃなくて.Netの方針なんですか?
(だとしたら言いたいことウズウズ)

>よこけんさん
>プリミティブ型 (整数、倍精度浮動小数点数など) に似た単一の値を論理的に表す。
>変更できない。
今回の肝はこれっぽいですね
要するに
・内部値を書き換えるメンバ関数禁止
・メンバ変数を取り出して書き換えるのも禁止
って事ですね

# re: [C#]構造を蒐集する程度の能力 2008/10/05 10:07 NyaRuRu

>追跡参照を用意しない方針ってのは知ってます

いえ,C# の話がしたいと言うよりは,

>ただ、本のタイトルからするとC#の方針じゃなくて.Netの方針なんですか?

・マネージポインタは .NET 1.x からあった
・.NET 1.x のころの MS の Verifier は,マネージポインタ(追跡参照)を返すメソッドを "not verifiable" と判定していた.
・STL/CLR でマネージポインタ(追跡参照)を返すメソッドを実際に必要になった.
・.NET 2.0 の MS の Verifier は、マネージポインタを返すメソッドを verifiable と判定するようになった.
・これは仕様の変更ではなくて,解釈の問題(.NET 1.x のころの MS の Verifier は,必要以上に厳しかった).

という歴史的経緯がありますよという話です.

タイトル  
名前  
Url
コメント