Vala 引用计数和参数传递

标签 vala reference-counting

在尝试使用 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 传递给 bar 时没有插入引用计数 (RC) 增量。据我所知,bar 中的第一行会将 foo 的 RC 递减为 0,这反过来应该释放 foo ,有效地使传递的变量 f 成为悬空指针,然后在 bar 的第二行访问它。但是,该程序执行没有问题,所以我不确定我是否在这里遗漏了一些东西,或者它只是纯属巧合。 这里生成的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;
}

最佳答案

这是正确的行为。仅计算 owned 引用。参数是 unowned,除非另有明确说明。因此 bar 中的 f 永远不会被引用计数,因为调用者负责维护引用计数。变量存储位置(类字段、堆栈变量、全局变量)都是拥有的

所以,让我们分别检查 mainbar:

main 创建了一个 Foo 的实例,它需要放在某个地方。它将它放在拥有它的全局变量 foo 中。现在通过 foo 创建的对象只有一个引用。然后我们调用 bar,它带有一个参数 foo。我们知道 foo 已经引用了该对象,并且将它作为参数传递不需要我们增加引用,除非参数是 owned。因此,我们只需将指针 foo 传递给 bar

bar 接受一个名为 fFoo 类型的参数,它不拥有。它将 null 分配给一个完全不相关的名为 foo 的全局变量,这会减少对象的引用计数,并在必要时将其清除。然后它对 f 中的字段进行赋值。

要“正确地”完成这项工作,编译器必须 1) 理解 foof 是相同的,即使您可以调用 bar 与任何参数,2) 知道减少 foo 上的引用计数与在某些情况下将其减少为零略有不同。对于无法解决停机问题的任何编译器来说,这实在是太复杂了。

要使您的代码按预期工作,您有两种选择:

  1. 将您的新对象分配给全局变量 foo 和您传递给 bar 的堆栈变量。您现在已通过调用 bar 确保变量保持事件状态。

  2. bar 使用 owned Foo f 而不是 Foo f。这将导致调用者在传递它之前递增 foo 上的引用,并在完成时递减 bar 上的引用。

简而言之,调用者有责任确保变量在将变量传递给方法时在该方法的生命周期内保持事件状态。您可以想象,当该方法为 async 时,情况会变得更加复杂。

关于Vala 引用计数和参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14396588/

相关文章:

vala - 如何从 Vala 中的字符串创建输入流

vala - Gee HashMap 包含方法作为值

c - 我如何在 Vala 中使用 CCode 属性?

C++ - 使用引用计数的基本垃圾收集器

c++ - 有共享引用计数智能指针这样的东西吗?

Java JNI 和 Vala - undefined symbol : g_once_init_enter

c# - 瓦拉会活下来吗?

ios - 为什么我应该在这种情况下使用自动释放?

c++ - C++ 中有一些更智能的智能指针吗?

delphi - 记录中的动态数组引用计数