g_object_weak_ref的意义和用途

g_object_weak_ref的 意义和用途

 

引用自:http://blog.csdn.net/absurd

 

引用计数是控制对象生命周期常用的手法,对象初始引用计数为一,引用一次计数加一,反引用一次计数减一,直到计数降为零时,对象被销毁。 GObject 也实现了引用计数机制, g_object_ref 函数用于引用,增加引用计数。 g_object_unref 函数用于反引用,减少引用计数。

 

GObject 还提供了另外两个函数 : g_object_weak_ref/g_object_weak_unref weak_ref 直译过来是弱引用,但它们的意义并不是很直观,新手常常很迷惑,本文介绍它们的意义和用途。我们先看看它们的函数原型:

void        g_object_weak_ref             (GObject        *object,

                            GWeakNotify     notify,

                           gpointer        data);

void        g_object_weak_unref           (GObject        *object,

                           GWeakNotify     notify,

                           gpointer         data);

 

g_object_ref/g_object_unref 相比, g_object_weak_ref/g_object_weak_unref 的原型要复杂许多,而且也看不出它们与引用 有何关系。但从文档和代码可以很容易知道, g_object_weak_ref 的功能就是注册一个回调函数,该函数将在对象被销毁时调用。

 

这与引用有什么关系呢?我们用一个例子说明:

 

在短信应用中,假设我们只允许一个写短信的窗口存在。要进入写短信界面,第一次创建写短信窗口,并把窗口句柄保存起来。这相当于引用了该窗口,但是我们不能调用 g_object_ref 去增加窗口的引用计数,原因是没适当的时候去反引用它,这会导致窗口无法关闭。

 

第二次进入时,先判断保存的窗口句柄是否为空,如果不为空,则认为窗口已经打开,直接把它提到前面来即可。

 

窗 口不存在就创建它,存在就重用它,保证只有一个写短信的窗口存在。但上面的逻辑是有漏洞的:假设写完短信,用户通过正当或者不正当的手段关闭该窗口。窗口 已经关闭了,但外面还保存着它的句柄,这个窗口句柄指向无效的内存,若仅仅以保存的窗口句柄是否为空,来判断窗口是否已经打开,就必然会出现错误。

 

窗口本身并不知道外面是否保存了它的句柄,它不可能在销毁时去把保存的句柄置为空。怎么办呢?最简单的办法就利用 g_object_weak_ref ,向窗口注册一个回调函数,窗口在销毁时调用该回调函数,在回调函数中,可以把保存的窗口句柄置为空。

 

简单的说: g_object_weak_ref 让引用者有机会知道,引用的对象是否已经无效了,这可以防止野指针的出现。对于窗口对象,要模拟实现 g_object_weak_ref 的功能,其实有好几种方法:比如用 GTK_IS_WIDGET 判断窗口是否还有效、用 g_object_set_data_full 注册回调函数,或者注册 GtkObject destroy 信号等。当然,只有 g_object_weak_ref 是名正言顺的,也只有它是最简单的。

 

~~end~~

 

==================================================

下面来看个具体的例子:

static void
call_weak_notify (gpointer data, GObject *dead_object)
{
  GList *list = data;

  list = g_list_remove (list, dead_object);
}

void
call_list_add (GList *list, Call *call)
{
  g_object_weak_ref (G_OBJECT (call), call_weak_notify, list);

  list = g_list_prepend (list, call);
}

void
call_list_remove (GList *list, Call *call)
{
  g_object_weak_unref (G_OBJECT (call), call_weak_notify, list);

  list = g_list_remove (list, call);
}
  

你可能感兴趣的:(.net,Blog)