3

Valaを試し、生成されたCソースコードを調べた後、次のValaコードを思いつきました。

class Foo : GLib.Object {
    public string baz;
}

class Main : GLib.Object {
    public static Foo foo;

    public static void bar(Foo f) {
        foo = null;
        f.baz = "Hi";
    }

    public static int main(string[] args) {
        foo = new Foo();
        bar(foo);
        return 0;
    }
}

生成されたCコードを調べると、Valaコンパイラーがfooの参照カウント(RC)増分をbarに渡すときに挿入しなかったことがわかりました。私が理解している限り、バーの最初の行はfooのRCを0にデクリメントします。これにより、fooが解放され渡された変数fがダングリングポインターになり、バーの2行目でアクセスされます。 。ただし、プログラムは問題なく実行されるため、ここで何かが欠落しているのか、それともまったくの偶然によって機能するのかはわかりません。参照用に生成されたCコードは次のとおりです。

void main_bar (Foo* f) {
    Foo* _tmp0_;
    gchar* _tmp1_;
    g_return_if_fail (f != NULL);
    _g_object_unref0 (main_foo);
    main_foo = NULL;
    _tmp0_ = f;
    _tmp1_ = g_strdup ("Hi");
    _g_free0 (_tmp0_->baz);
    _tmp0_->baz = _tmp1_;
}

gint main_main (gchar** args, int args_length1) {
    gint result = 0;
    Foo* _tmp0_;
    Foo* _tmp1_;
    _tmp0_ = foo_new ();
    _g_object_unref0 (main_foo);
    main_foo = _tmp0_;
    _tmp1_ = main_foo;
    main_bar (_tmp1_);
    result = 0;
    return result;
}
4

1 に答える 1

2

これは正しい動作です。参照のみownedがカウントされます。unowned特に明示的に指定されていない限り、パラメータはです。したがってfbarでは、呼び出し元が参照カウントを維持する責任があるため、参照カウントは行われません。変数の格納場所(クラスフィールド、スタック変数、グローバル変数)はすべてownedです。

それでは、個別に調べmainてみましょう。bar

mainのインスタンスを作成しますFoo。これはどこかに配置する必要があります。それfooを所有するグローバル変数に入れます。これで、を介して作成されたオブジェクトに単一の参照がありますfoobar次に、パラメータをとるを呼び出しますfoofooすでにオブジェクトを参照しており、パラメーターとして渡す場合、パラメーターが。でない限り、参照をインクリメントする必要はありませんowned。したがって、ポインタfooをに渡すだけbarです。

bar所有していないFooというタイプのパラメータを取ります。fと呼ばれる完全に無関係なグローバル変数にnullを割り当てますfoo。これにより、オブジェクトの参照カウントが減少し、必要に応じてクリーンアップされます。次に、のフィールドに割り当てを行いfます。

この動作を「正しく」行うには、コンパイラは1)パラメータを使用して呼び出すことができる場合でも、同じであることfooを理解する必要があります。2)参照カウントをデクリメントすることは、場合によってはゼロにデクリメントすることとは少し異なることを知っている必要があります。 。これは、停止性問題を解くことができないコンパイラにとっては非常に複雑です。fbarfoo

コードを期待どおりに機能させるには、次の2つのオプションがあります。

  1. foo新しいオブジェクトを、に渡すグローバル変数とスタック変数の両方に割り当てますbar。これで、への呼び出しを通じて変数が有効なままであることを確認できましたbar

  2. の代わりにbarテイクしてください。これにより、呼び出し元は参照を渡す前に参照をインクリメントし、参照が完了すると参照をデクリメントします。owned Foo fFoo ffoobar

つまり、変数がメソッドに渡されたときに、そのメソッドの存続期間中、変数が有効なままであることを確認するのは、呼び出し元の責任です。その方法がであるとき、それはもう少し複雑になることを想像することができますasync

于 2013-01-18T14:33:15.003 に答える