21-1で示したとおりである。どんな変数への参照でも取得できるわけではない。21-3は、クラスのインスタンスなど幾つかの種類の変数に&演算子を適用してみた例である。変数のアドレスまたはサイズを取得できません。変数のアドレスまたはサイズを取得できません。ないステートメントのアドレスのみを取得できます。式のアドレスを取得できません。21-3これを実行するとFig.21-4のようになる。Fig.21-4コンパイル・エラーになる組み合わせはコメントアウトしてある。17〜19行目のローカルな整数型変数への参照は問題なく処理されていることが分かる。20〜24行目でクラスのインスタンスの参照を得ることは、コンパイル・エラーになってしまってできない。25〜28行目はローカルな構造体への参照を得ているが、これは正常にコンパイル実行できる。29〜33行目は構造体をボックス化してインスタンス化しているが、この場合もコンパイラがエラーにする。このようにコンパイルできるものとできないものに分かれた理由は、データを格納するメモリには2つの種類が存在することによる。1つは固定変数、もう1つは移動可能変数である。Frameworkのメモリ管理機構のメモリ整理によって位置が移動しないもの、移動可能変数は移動してしまう可能性があるものだ。参照を取得できるのは固定変数に限られる。移動可能変数では、参照先が移動してどこかに行ってしまう可能性があり、参照できても正常に処理できないのである。ローカル変数はスタック上に確保されるが、スタックは基本的に移動しないものであるため、これに対する参照は問題なく得られる。これが17〜19行目の処理がうまく動く理由だ。次に、20〜24行目もローカル変数のように見えるが、実際のインスタンス本体はスタック外に移動可能変数として確保されるので、これは参照できない。25〜28行目は構造体の例だが、クラスと違って、ローカル変数として確保すれば中身のすべてがスタック上に存在するため、参照を取得できる。29〜33行目のように、構造体をボックス化するとスタック外に移動可能変数として確保されてしまうので、参照は取得できない。移動可能変数メモリを参照するfixedステートメント移動可能変数メモリへの参照は、何もしなければ得ることができない。得る方法がないわけではない。fixedステートメントは、移動可能変数メモリを一時的に固定させ、それに対する参照を得られるようにする機能を持つ。21-4はそれを用いた例である。変数のアドレスまたはサイズを取得できません。変数のアドレスまたはサイズを取得できません。ステートメントを使用する必要はありません。式のアドレスを取得できません。21-4これを実行するとFig.21-5のようになる。21-3の例とほぼ同じだが、fixedステートメントを使用するようになっている。21-3で駄目だったインスタンスへの参照だが、21〜27行目を見るとおり、やはりエラーになっていることが分かると思う。これは移動可能変数は固定できないということではない。28〜31行目のように、クラスのメンバを指定すると固定することができる。21-3でも駄目だったが、fixedステートメントを適用してもやはり駄目であった。これは、移動可能変数を固定できないためではなく、fixedステートメントの括弧内がキャストを含む複雑な式になっているためだ。式のデータ型の記述が複雑化すると、固定すべきメモリの正しい位置が分かりにくくなり、うまく機能しないようだ。fixedステートメントを使う場合は、28行目のようなシンプルな式を書くように心掛けるとよいかもしれない。配列にポインタ・アクセスするC/C++では、配列にポインタでアクセスする方法がよく使われていたが、C#でも可能である。21-5はそれを記述した例である。21-5これを実行するとFig.21-6のようになる。Fig.21-67〜15行目は、「安全でないコード」を使わないメソッドで、16〜29行目は同じ結果を出すように「安全でないコード」を用いて記述した例である。配列は移動可能変数なので、19行目のfixedステートメントで一時的に固定している。20〜27行目の範囲内なら、ポインタ変数のpArrayを通じて、配列にアクセスすることができる。見ると、19行目で指定されているのは、配列の0番目の要素だけである。配列は1つの塊としてメモリ上に確保されているので、1個の要素を固定すればすべての要素も同時に固定されるのである。25行目のように、ポインタにも++や--演算子が使用できる。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。