「値のコピー」か「住所の共有」か。VB.NETの構造体とクラスの決定的な違いをマスターしよう
こんにちは。現場で長くコードと向き合っていると、初学者が最初に必ずと言っていいほど直面する「不思議なバグ」があります。
「代入したはずなのに、なぜか元のデータまで書き換わっている……?」
この現象、実はVB.NETの「値型(Structure)」と「参照型(Class)」というメモリの挙動を理解していないときに起こる典型的なミスなんです。ここさえ押さえれば、あなたのコードの堅牢性は劇的に向上します。さあ、メモリの裏側を覗いてみましょう。
—
1. 構造体(Structure)とクラス(Class)の正体
VB.NETにおいて、データを定義する際に使うのが `Structure` と `Class` です。一見すると似たような書き心地ですが、メモリの扱い方は全くの別物です。
構造体(Structure):値そのものを運ぶ「コピー機」
構造体は「値型」です。変数を代入すると、データそのものが別の場所に複製(コピー)されます。
クラス(Class):住所を指し示す「名刺」
クラスは「参照型」です。変数を代入してもデータはコピーされません。「データが置かれているメモリ上の住所」を共有するだけなのです。
—
2. 決定的な違いをコードで体感する
言葉だけではイメージしづらいですね。実際にコードを動かして、この「挙動の差」を見てみましょう。
構造体(Structure)の挙動:独立したコピーが作られる
Structure PointStruct
Public X As Integer
Public Y As Integer
End Structure
Sub StructureExample()
Dim p1 As New PointStruct With {.X = 10, .Y = 20}
Dim p2 As PointStruct = p1 ‘ p1の値を「コピー」する
p2.X = 99 ‘ p2を書き換えても…
‘ p1は10のまま。影響を受けない
Console.WriteLine($”p1.X={p1.X}, p2.X={p2.X}”)
End Sub
構造体は「自分の値」を自分の中に持っています。だから、コピーを作ってもお互いは全くの他人として生きるのです。
クラス(Class)の挙動:同じ場所を指し示す「共有」
Class PointClass
Public X As Integer
Public Y As Integer
End Class
Sub ClassExample()
Dim c1 As New PointClass With {.X = 10, .Y = 20}
Dim c2 As PointClass = c1 ‘ c1の「住所」をコピーする
c2.X = 99 ‘ c2の指し示す住所にあるXを書き換えると…
‘ c1も同じ住所を見ているため、連動して書き換わってしまう!
Console.WriteLine($”c1.X={c1.X}, c2.X={c2.X}”)
End Sub
これが「意図しない書き換え」の正体です。`c2` を変えたつもりが、`c1` も巻き添えを食らっています。
—
3. なぜこの違いを知る必要があるのか?
実務の現場では、この挙動を知らないと致命的なバグを生みます。
- 構造体(Structure)を選ぶべき時:
- 座標や色、小さな数値の集合など、「値そのもの」として扱いたい場合。
- 小さいデータ(16バイト以下が目安)であれば、クラスよりもメモリ効率が良く、高速に動作します。
- クラス(Class)を選ぶべき時:
- 大きなデータや、複雑なロジックを持つオブジェクト。
- 「実体は一つ」であることを管理したい場合(例:ユーザー情報、データベースのレコードなど)。
—
4. 今日から使える「バグを防ぐ」鉄則
初心者のうちから、以下のルールを意識するだけで、あなたのコードは格段にプロフェッショナルになります。
1. 「連動して困るもの」は構造体にするな
データの一部を書き換えたときに、他へ影響を与えてほしくないなら、基本は `Class` を使いましょう。
2. 不変(Immutable)を意識する
クラスを作る際、不用意に値を書き換えられないように `ReadOnly` プロパティを使う習慣をつけましょう。これにより、意図しない参照先の書き換えを防げます。
3. 深いコピー(Deep Copy)を知る
どうしてもクラスを「別の実体」としてコピーしたい場合は、`MemberwiseClone` メソッド等を使って、住所ではなくデータの中身を複製する工夫が必要です。
—
まとめ:メモリを支配する者がコードを制す
VB.NETの構造体とクラスは、単なる書き方の違いではありません。「値そのものを扱うのか、それとも住所を共有するのか」という、メモリ管理の設計思想の違いです。
- 構造体 = コピーを作る(独立している)
- クラス = 住所を共有する(影響し合う)
この視点を持つだけで、プログラムの挙動が予測可能になります。「なぜ動くのか?」が分かれば、バグはもう怖くありません。
ここをクリアすれば、あなたはもう脱初心者です。自信を持って、次のステップへ進んでいきましょう!応援しています。
