A3サイズの升目帖(旧)

ゲーム制作やプログラミングに関する雑記

【D言語】クラスのインスタンスをスタック上に構築する

D言語のロゴマーク


サイズの小さいクラスを関数内でサクッと使い捨てしたいことが稀にある。

そういうインスタンスは、ヒープ上ではなくスタック上に確保したくなるのが人情というもの。

で、D言語ではそれができるのだが、個人的に「あれ?やり方とか色々どうだっけ?」となりがちなので備忘録としてメモ。

dmd 2.098.0 で動作確認。


結論

例えば Color というクラスがあったとして、以下の一文でインスタンスをスタック上に構築できる。

scope c = new Color();

scope で変数が修飾されているのがポイントだ。

変数定義を単に auto c とか Color c とかにしてしまうと、ヒープ上に確保されGCの管理下に入る。


その他補足

補足1

クラスのコンストラクタとデストラクタが @nogc なら、new しているにもかかわらず関数を @nogc で修飾できるらしい。すごい。

void func() @nogc // <- 関数を @nogc にできる!
{
    scope c = new Color(); // <- "new" してるのに! やったね!
}

当然、デストラクタはスコープを抜ける際に 即時 呼び出される。

補足2

スタックへの参照なので、外部に漏れるとマズい。

しかし、関数が @safe で修飾されていれば、参照を逃がそうとするコードはすべてコンパイルエラーになるので安心だ。

Color g_Color;

Color func() @nogc @safe // <- @safeコード下なので…
{
    scope c = new Color();

    // ↓こいつらはコンパイルがそもそも通りません。助かったぜ。
    version (none)
    {
        g_Color = c;

        return c;
    }
}


未検証のこと

@nogc 関数内で、でかいインスタンスをスタックに作ろうとするとどうなるんかね?

C#stackalloc みたいに StackOverflow 的なエラーになるなら、閾値はどんなもんなんだろう?

プリミティブ型のメンバを2,3持つ程度のクラスなら、まあまず大丈夫だろうから、個人的には問題にはならなさそうではあるが…

こんど時間に余裕があったら調べてみよう。

-preview=in の参照渡し境界サイズみたいに、環境依存とかだったら怖いからね…