VB.NET C# データ型の基本 | |
|
PCのメモリーの構造
VB.NETやC#のデータ型を理解する為にはPC上のメモリーの構成の最低限の知識が必要となります。 PC上のメモリは大きく分けて3つの種類が有ります、下の表を御覧下さい。 この内レジスタはCPUが演算などを行なう為のもので、VB.NETやC#などから操作することは出来ません。 ヒープはプログラムが必要なときにメモリー上に確保され、不要になったときは廃棄されます。 スタックはコンパイラによって確保されヒープより高速で使用されます。
スタック
上の図は通常のEXEファイルのメモリー構成を示したものです。スタックは実行ファイルの隣の領域に配置され、特別な方法で使用されます。 例えば int i =10; (C#) Dim i As Integer (VB.NET)の変数を関数Aから関数Bに渡す場合を 考えて見ましょう。 関数Aから関数Bを引数付きで呼び出すと、A関数はスタック上の自分の領域の 後ろに引数をコピーして、先頭のアドレスをB関数に渡します。 一方B関数はA関数からスタック上のアドレスを渡され又データの大きさは判っているので、 この引数の値を読み込むことが可能です。 又B関数が使用するローカルの変数もこのスタック上に保存されます。 更にB関数から呼び出されるC関数への引数及びC関数のローカル変数の領域はB関数の下に 確保されます。 さてB関数の処理が終わってA関数に処理が戻ると、スタック上のB関数の領域はA関数にとっては もう無関係です、もし再びA関数がB関数を呼び出すとしても、新しくA関数の下のスタックに引数を書き込み 新しくB関数のローカル変数の領域を確保します。 スタックは順番に使用される為に、スタック上のデータは使用が終わっても開放する必要が有りません。 次の関数のデータを書き込む場所を示すポインターを管理すれば良いことになります。 スタックを使用すると、引数をスタックにコピーする為、元の変数の値を渡した関数上で変えることが出来ません。 この方法はCall by Valuと呼ばれる方法で、日本語では「値渡し」と言い、C言語の優れた点とされています。 ただしプログラムの構成によっては、渡した値を変えることで、元の値を変えたい場合が有ります、 この場合は変数のアドレスを渡します。 変数のアドレスを渡すと、渡された側で元の変数を変えることが出来るのです。 では配列などの大きいデータを受け渡す場合や、関数間で共有するデータの引渡しはどのようにするのでしょうか? 値型と参照型
実はデータには値型と参照型の2種類が有り、今までは値型のみを述べてきました。 これに対してクラスのインスタンスや配列は参照型と呼ばれて、メモリーのヒープ領域に保存されます。 このヒープ上に確保されたデータを他の関数に引き渡す場合はそのアドレスがスタックに積まれて、 引き渡されるのです。
値渡しだけれど値が変わってしまった。!
ここで注意する事は、値渡しで渡されたデータは渡された側では変えられないと思っている人が多いことだ。次のコードを見て欲しい。 C# 値渡しサンプル2
class Program VB.NET 値渡しサンプル
Module Module1
このコードの実行結果は「kota」で見事に値が変わっている。
では次のコードはいかがであろうか。 C# 値渡しサンプル2
class Program VB.NET 値渡しサンプル2
Module Module1 この結果は「nero」で今度は呼び出し元のデータは変わってい。 これは一体何を意味するのだろうか? 参照型データを値渡しで渡すとアドレスのコピーがスタックに積まれて渡される。 たとえコピーであっても其のアドレスが指し示す物は同じであろう、従ってクラスのインスタンスの フィールドの「name」は値渡しで有っても変えられてしまったので有る。 それでは2番目のコードはいかがであろうか? 渡された物は確かにアドレスのコピーで有るが、其のアドレスのコピーそのものが、 渡された側で書き換えられたのである、従って渡した側のインスタンスは書き返られなかった のである。 値渡しで有れば大丈夫だと言う神話はここでは通用しない。 値渡しが意味を持つのは、渡された引数に直接別のオブジェクトを代入する時だけである。 この点を間違えると大変深刻なバグを発生させることになるので十分注意をされたい。 値方、参照型のスピード
スタックの操作はCPUの構造上高速です。ただし値型の中で構造体は大きなデータを持つことが出来、これを値渡しにするとスタックに対して 大量のコピーが発生し、パフォーマンスが落ちることになります。 実は構造体とクラスは殆ど違いが有りませんが、構造体は値型でスタック上に保存され、 クラスはヒープ上に保存されます。 構造体で大きなデータになる物はクラスに変更する方が良いでしょう。 クラスに変更できない場合は値渡しではなく参照渡しとすることも可能です。 |