c#の構造体(struct)は結構前からどういった存在なのか気になっていました。
クラスとの違いはどの部分なのか、どのようなメリットがあるのか、など知っておけば、パフォーマンスを加味したコードを書けるのではないか。
これまで個人的に全く使って来ていなかったのですが、少し時間をとって調べてみました。
構造体
とりあえず適当に構造体を作ってみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public struct StructTest { private int _id; private string _name; public int Id { get { return _id; } } public string Name { get { return _name; } } public StructTest(int id, string name) { _id = id; _name = name; } public void SetId(int id) { _id = id; } } |
構造体を作成する時に struct を名前の前につけます。
1 2 3 4 |
public struct Hoge { } |
これを任意の場所で利用をします。
1 2 3 |
var test = new StructTest(1, "たろう"); Debug.Log(test.Id); // 1 Debug.Log(test.Name); // たろう |
値型 参照型
構造体は「値型」と呼ばれています。- メモリ管理がスタックなので、宣言した時点でメモリが確保される
- 値渡し
メモリ管理 スタック
メモリ管理には「ヒープ型」「スタック型」があります。構造体は「スタック」でクラスは「ヒープ」で管理されています。
- ヒープ:GC(ガベージコレクション)で解放
- スタック:スコープを抜けた時に解放
ヒープ型の場合、GCが走る時にUnityでは結構は負荷がかかります。
メモリ管理についてはこちらのスライドがわかりやすかったです。
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
値渡し
「値渡し」の場合次のような挙動になります。
1 2 3 4 5 6 7 |
var hoge = new StructTest(); var hoge2 = hoge; Debug.Log(hoge.Id); // 0 Debug.Log(hoge2.Id); // 0 hoge.SetId(19); Debug.Log(hoge.Id); // 19 Debug.Log(hoge2.Id);// 0 |
構造体の場合、それぞれの変数が独立(値を渡し)しています。
hogeの値を変更してもhoge2には反映されません。
クラスの場合「参照型」になるので、値の変更が反映されます。
構造体でできないこと
クラスでできることが構造体でできない場合があります。- 継承ができない
- staticが定義できない
1 2 3 4 5 6 7 8 9 10 11 |
// 継承できない public struct StructChild : StructTest { } // staticな構造体は作れない public static struct StructTest { } |
最後に
今回構造体について色々調べてみたのですが、実際に使い所がいまいちよくわかりませんでした。使い方については公式ではこのような記載がありました。
構造体の仕様 (C# プログラミング ガイド)
クラスまたは構造体の選択
上記を読むとメモリ解放周りでメリットがありそうに感じますが、実際にそこまでシビアな状況がないので、とりあえずはクラスで定義してメモリの仕様状況によって構造体を考えていこうかと思いました。
