g_object_weak_ref的意义和用途
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:Li XianJing <xianjimli at hotmail dot com>
更新时间:2007-1-17
引用计数是控制对象生命周期常用的手法,对象初始引用计数为一,引用一次计数加一,反引用一次计数减一,直到计数降为零时,对象被销毁。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~~