C#2.0時代のゲームプログラミング(29)


■ delegateの実装的な観点から


intのような値型はstack上に確保されるのではなかったのか?intが本当にstack上に確保されているのならば、delegateの中からそのstack上の値をポイントしていると、この関数から抜けてstackが巻き戻されてしまったときにそのようなポインタは不正なポインタになってしまわないのだろうか?どうやって実装しているのだろう?


簡単に言ってしまえば、上のようなdelegateのなかでstack上の変数を参照した場合、その変数をstack上に配置するのではなく、最初からheap上に配置するような実装になっている、ということである。


そして、deleagteのなかでは、そのheap上の変数を指すようになっている。だから、先ほどのプログラムの結果は2になる。(参考として id:NyaRuRu:20051029 を挙げておく。)



001 TestDelegate[] d = new TestDelegate[5];
002 for ( int i = 0 ; i < 5 ; ++i )
003 {
004 d[i] = delegate
005 {
006 Console.WriteLine(i.ToString());
007 };
008 }
009 for ( int i = 0 ; i < 5 ; ++i )
010 d[i](); // 5,5,5,5,5が表示される
011
012

例えば、上のプログラムならば、5,5,5,5,5が表示される。delegateのなかでiを使っているのでiはheap上に確保され、forループを抜けたあとも生き続けるからだ。



001 TestDelegate[] d = new TestDelegate[5];
002 for ( int i = 0 ; i < 5 ; ++i )
003 {
004 int j = i;
005 d[i] = delegate
006 {
007 Console.WriteLine(j.ToString());
008 };
009 }
010 for ( int i = 0 ; i < 5 ; ++i )
011 d[i](); // 0,1,2,3,4が表示される
012

上のプログラムは違う。ローカル変数jを用意している。jはdelegateのなかで使用されているので、heap上に確保される。int jを実行するたびにheap上にint型変数を確保される。iはdelegateのなかで使用されていないので通常通りstack上に確保されている。よって、ひとつ目のforを抜けたとき、jのインスタンスは5個がheap上に残っていて、5つのdelegateからそれぞれのjのインスタンスを指している状態になる。(つづく)