4_13_GLib库入门与实践_数据列表

简介

(本段内容翻译自官方文档)
数据列表提供任意数据元素的列表,可以使用字符串或与字符串的GQuark访问这些数据元素。
GQuark方法更快,因为无论如何都必须将字符串转换为 GQuarks。

  • 数据列表用于将任意数据与 GObject 相关联,使用 g_object_set_data()和相关函数。
  • 要创建数据列表,请使用 g_datalist_init()。
  • 要将数据元素添加到数据列表,请使用 g_datalist_id_set_data()、g_datalist_id_set_data_full()、g_datalist_set_data() 和 g_datalist_set_data_full()。
  • 要从数据列表中获取数据元素,请使用 g_datalist_id_get_data()和g_datalist_get_data()。
  • 要遍历数据列表中的所有数据元素,请使用 g_datalist_foreach()(非线程安全)。
  • 要从数据列表中删除数据元素,请使用 g_datalist_id_remove_data()和g_datalist_remove_data()。
  • 要从数据列表中删除所有数据元素,请使用 g_datalist_clear()。

数据结构

GData是一个不透明的数据结构。

typedef struct _GData GData;

函数列表

void 	g_datalist_init ()
#define 	g_datalist_id_set_data()
void 	g_datalist_id_set_data_full ()
gpointer 	g_datalist_id_get_data ()
#define 	g_datalist_id_remove_data()
gpointer 	g_datalist_id_remove_no_notify ()
gpointer 	(*GDuplicateFunc) ()
gpointer 	g_datalist_id_dup_data ()
gboolean 	g_datalist_id_replace_data ()
#define 	g_datalist_set_data()
#define 	g_datalist_set_data_full()
gpointer 	g_datalist_get_data ()
#define 	g_datalist_remove_data()
#define 	g_datalist_remove_no_notify()
void 	g_datalist_foreach ()
void 	g_datalist_clear ()
void 	g_datalist_set_flags ()
void 	g_datalist_unset_flags ()
guint 	g_datalist_get_flags ()

函数功能分类

整体上来讲,数据列表可以分为两大类:

  • g_data_list_id_xxx:将一个GQuark与一个任意元素数据相关联的一组操作函数
  • g_data_list_xxx:是将一个字符串与一个任意元素数据相关联的一组操作函数

函数功能说明及综合演示

初始化

将datalist初始化为空,如果该datalist有指向堆上的内存,初始化前需要先释放该内存以避免内存泄露。

g_datalist_init ()
插入

带full的函数,可以自定义元素的释放函数。
注意:插入的数据不会被复制,因此局部变量、函数结束被自动释放的变量不可插入到数据列表。
如果插入的key已经存在,且存在元素自定义释放函数,该key对应的元素会被释放函数释放,新的元素将被插入。

g_datalist_id_set_data()
g_datalist_id_set_data_full ()

下面演示插入两种不同的数据,一种是固定长度的结构体(内部无指针),一种是非固定长度的结构体(内部有指针)。

固定长度结构体插入
示例代码如下:
源码见glib_examples\glib_datalist\glib_datalist_struct_no_pointer

#include <glib.h>

typedef struct my_data_tag {
    gint x;
    gint y;
}my_data_t;

static void g_datalist_id_test (void)
{
    GData *list = NULL;
    my_data_t *data1 = NULL;
    my_data_t *data2 = NULL;
    my_data_t *data3 = NULL;
    my_data_t *ret = NULL;

    g_datalist_init (&list);

    data1 = g_new0(my_data_t, 1);
    data1->x = 101;
    data1->y = 201;
    data2 = g_new0(my_data_t, 1);
    data2->x = 102;
    data2->y = 202;
    data3 = g_new0(my_data_t, 1);
    data3->x = 103;
    data3->y = 203;

    g_print("data1->x(%p): %d, data1->y(%p):%d \n", &data1->x, data1->x, &data1->y, data1->y);

    g_datalist_id_set_data (&list, g_quark_from_string ("one"), data1);
    g_datalist_id_set_data (&list, g_quark_from_string ("two"), data2);
    g_datalist_id_set_data (&list, g_quark_from_string ("three"), data3);

    ret = g_datalist_id_get_data (&list, g_quark_from_string ("one"));
    g_print("ret->x(%p): %d, ret->y(%p):%d \n", &ret->x, ret->x, &ret->y, ret->y);

    g_free(data1);
    g_free(data2);
    g_free(data3);
    g_datalist_clear (&list);
}

int main (int argc, char** argv)
{
    g_datalist_id_test();

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_datalist_struct_no_pointer
data1->x(0x2193dc0): 101, data1->y(0x2193dc4):201
ret->x(0x2193dc0): 101, ret->y(0x2193dc4):201

非固定长度结构体插入
示例代码如下:
源码见glib_examples\glib_datalist\glib_datalist_struct_with_pointer

#include <glib.h>

typedef struct my_data_tag {
    gint id;
    gchar *name;
}my_data_t;

static void _datalist_id_destroy_func(gpointer data)
{
    my_data_t *p = (my_data_t *)data;
    if(NULL == p) {
        return;
    }

    g_print("destroy %s! \n", p->name);

    g_free(p->name);
    g_free(p);
}

static void g_datalist_id_test (void)
{
    GData *list = NULL;
    my_data_t *data1 = NULL;
    my_data_t *data2 = NULL;
    my_data_t *data3 = NULL;
    my_data_t *ret = NULL;

    g_datalist_init (&list);

    data1 = g_new0(my_data_t, 1);
    data1->id = 100;
    data1->name = g_strdup_printf("name:%d", data1->id);
    data2 = g_new0(my_data_t, 1);
    data2->id = 101;
    data2->name = g_strdup_printf("name:%d", data2->id);
    data3 = g_new0(my_data_t, 1);
    data3->id = 102;
    data3->name = g_strdup_printf("name:%d", data3->id);

    g_print("data1->id(%p): %d \n", &data1->id, data1->id);
    g_print("data1->name(%p): %s \n", data1->name, data1->name);

    g_datalist_id_set_data_full(&list, g_quark_from_string ("one"), data1, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("two"), data2, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("three"), data3, _datalist_id_destroy_func);

    ret = g_datalist_id_get_data (&list, g_quark_from_string ("one"));

    g_print("ret->id(%p): %d \n", &ret->id, ret->id);
    g_print("ret->name(%p): %s \n", ret->name, ret->name);

    g_datalist_clear (&list);
}

int main (int argc, char** argv)
{
    g_datalist_id_test();

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_datalist_struct_with_pointer/glib_datalist_struct_with_pointer
data1->id(0x13eadc0): 100
data1->name(0x13eae50): name:100
ret->id(0x13eadc0): 100
ret->name(0x13eae50): name:100
destroy name:100!
destroy name:101!
destroy name:102!

下面演示一下g_datalist_id_set_data_full函数替换数据列表中已有数据的情况。
示例代码如下:
源码见glib_examples\glib_datalist\glib_datalist_set_data_full

#include <glib.h>

typedef struct my_data_tag {
    gint id;
    gchar *name;
}my_data_t;

static void _datalist_id_destroy_func(gpointer data)
{
    my_data_t *p = (my_data_t *)data;
    if(NULL == p) {
        return;
    }

    g_print("destroy %s! \n", p->name);

    g_free(p->name);
    g_free(p);
}

static void g_datalist_id_test (void)
{
    GData *list = NULL;
    my_data_t *data1 = NULL;
    my_data_t *data2 = NULL;
    my_data_t *data3 = NULL;
    my_data_t *data4 = NULL;
    my_data_t *ret = NULL;

    g_datalist_init (&list);

    data1 = g_new0(my_data_t, 1);
    data1->id = 101;
    data1->name = g_strdup_printf("name:%d", data1->id);
    data2 = g_new0(my_data_t, 1);
    data2->id = 102;
    data2->name = g_strdup_printf("name:%d", data2->id);
    data3 = g_new0(my_data_t, 1);
    data3->id = 103;
    data3->name = g_strdup_printf("name:%d", data3->id);
    data4 = g_new0(my_data_t, 1);
    data4->id = 104;
    data4->name = g_strdup_printf("name:%d", data4->id);

    g_print("data2->id(%p): %d \n", &data2->id, data2->id);
    g_print("data2->name(%p): %s \n", data2->name, data2->name);

    g_datalist_id_set_data_full(&list, g_quark_from_string ("one"), data1, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("two"), data2, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("three"), data3, _datalist_id_destroy_func);

    g_print("before set_data_full: two \n");
    g_datalist_id_set_data_full(&list, g_quark_from_string ("two"), data4, _datalist_id_destroy_func);
    g_print("after set_data_full: two \n");

    ret = g_datalist_id_get_data (&list, g_quark_from_string ("two"));

    g_print("ret->id(%p): %d \n", &ret->id, ret->id);
    g_print("ret->name(%p): %s \n", ret->name, ret->name);

    g_datalist_clear (&list);
}

int main (int argc, char** argv)
{
    g_datalist_id_test();

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_datalist_set_data_full
data2->id(0x610e70): 102
data2->name(0x610e90): name:102
before set_data_full: two
destroy name:102!
after set_data_full: two
ret->id(0x610ef0): 104
ret->name(0x610f10): name:104
destroy name:101!
destroy name:104!
destroy name:103!
获取
// 获取元素的一份拷贝而不是元素本身
g_datalist_id_get_data
// 本函数内部加锁,当获取元素数据时,其他函数不可修改其值,因此是线程安全的。
g_datalist_id_dup_data 
替换
// 替换数据列表中的元素。
g_datalist_id_replace_data

示例代码如下:
源码见glib_examples\glib_datalist\glib_datalist_replace

#include <glib.h>

typedef struct my_data_tag {
    gint id;
    gchar *name;
}my_data_t;

static void _datalist_new_id_destroy_func(gpointer data)
{
    my_data_t *p = (my_data_t *)data;
    if(NULL == p) {
        return;
    }

    g_print("new destroy %d! \n", p->id);

    g_free(p);
}

static void _datalist_id_destroy_func(gpointer data)
{
    my_data_t *p = (my_data_t *)data;
    if(NULL == p) {
        return;
    }

    g_print("destroy %s! \n", p->name);

    g_free(p->name);
    g_free(p);
}

static void g_datalist_id_test (void)
{
    GData *list = NULL;
    my_data_t *data1 = NULL;
    my_data_t *data2 = NULL;
    my_data_t *data3 = NULL;
    my_data_t *data4 = NULL;
    my_data_t *old_data = NULL;
    my_data_t *ret = NULL;
    GDestroyNotify old_destroy;

    g_datalist_init (&list);

    data1 = g_new0(my_data_t, 1);
    data1->id = 101;
    data1->name = g_strdup_printf("name:%d", data1->id);
    data2 = g_new0(my_data_t, 1);
    data2->id = 102;
    data2->name = g_strdup_printf("name:%d", data2->id);
    data3 = g_new0(my_data_t, 1);
    data3->id = 103;
    data3->name = g_strdup_printf("name:%d", data3->id);
    data4 = g_new0(my_data_t, 1);
    data4->id = 104;
    //data4->name = g_strdup_printf("name:%d", data4->id);

    g_print("data2->id(%p): %d \n", &data2->id, data2->id);
    g_print("data2->name(%p): %s \n", data2->name, data2->name);

    g_datalist_id_set_data_full(&list, g_quark_from_string ("one"), data1, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("two"), data2, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("three"), data3, _datalist_id_destroy_func);

    old_data = g_datalist_id_get_data(&list, g_quark_from_string ("two"));
    if(NULL == old_data) {
        g_print("can't find key: two \n");
        g_datalist_clear(&list);
        return;
    }
    g_print("before set_data_full: two \n");
    g_datalist_id_replace_data(&list, g_quark_from_string ("two"), old_data, data4, _datalist_new_id_destroy_func, &old_destroy);
    if(NULL != old_destroy) {
        old_destroy(data2);
    }
    g_print("after set_data_full: two \n");

    ret = g_datalist_id_get_data (&list, g_quark_from_string ("two"));

    g_print("ret->id(%p): %d \n", &ret->id, ret->id);
    //g_print("ret->name(%p): %s \n", ret->name, ret->name);

    g_datalist_clear (&list);
}

int main (int argc, char** argv)
{
    g_datalist_id_test();

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_datalist_replace
data2->id(0x23b4e70): 102
data2->name(0x23b4e90): name:102
before set_data_full: two
destroy name:102!
after set_data_full: two
ret->id(0x23b4ef0): 104
destroy name:101!
new destroy 104!
destroy name:103!

上述示例程序有三个需要注意的地方:

  1. old_data必须是已经存在于列表中的一个元素,手动构造出的,即使值完全一致,也不可以。
  2. 被替换的元素不会被自动释放,需要手动调用其释放函数。
  3. 新插入的元素,自带一个释放函数,可以和之前的释放函数不一样。列表清空或销毁时,会自动调用对应的元素释放函数。
    一般来说,数组,链表,队列,hash,树,其每个节点的类型都是相同的,但我们可以使用g_datalist_id_replace_data构造一个数据元素类型不同的数据列表。
    举例:数据列表有ABCD四个类型为char *的元素,E为一个结构体,可以通过本函数替代C,得到ABED数据列表,其中ABD为char*型元素,E为结构体元素。

g_datalist_xxx没有replace函数,因此每个元素的类型都是相同的,可以使用提供的foreach对元素进行遍历。

删除
// 删除元素,元素释放函数会被自动调用
g_datalist_id_remove_data()
// 删除元素,元素释放函数不会被自动调用,用户需手动释放内存
g_datalist_id_remove_no_notify ()

示例代码如下:
源码见glib_examples\glib_datalist\glib_datalist_delete

#include <glib.h>

typedef struct my_data_tag {
    gint id;
    gchar *name;
}my_data_t;

static void _datalist_id_destroy_func(gpointer data)
{
    my_data_t *p = (my_data_t *)data;
    if(NULL == p) {
        return;
    }

    g_print("destroy %s! \n", p->name);

    g_free(p->name);
    g_free(p);
}

static void g_datalist_id_test (void)
{
    GData *list = NULL;
    my_data_t *data1 = NULL;
    my_data_t *data2 = NULL;
    my_data_t *data3 = NULL;
    my_data_t *data4 = NULL;
    my_data_t *del_data = NULL;
    my_data_t *ret = NULL;

    g_datalist_init (&list);

    data1 = g_new0(my_data_t, 1);
    data1->id = 101;
    data1->name = g_strdup_printf("name:%d", data1->id);
    data2 = g_new0(my_data_t, 1);
    data2->id = 102;
    data2->name = g_strdup_printf("name:%d", data2->id);
    data3 = g_new0(my_data_t, 1);
    data3->id = 103;
    data3->name = g_strdup_printf("name:%d", data3->id);
    data4 = g_new0(my_data_t, 1);
    data4->id = 104;
    data4->name = g_strdup_printf("name:%d", data4->id);

    g_datalist_id_set_data_full(&list, g_quark_from_string ("one"), data1, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("two"), data2, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("three"), data3, _datalist_id_destroy_func);
    g_datalist_id_set_data_full(&list, g_quark_from_string ("four"), data4, _datalist_id_destroy_func);

    g_datalist_remove_data(&list, "two");

    del_data = g_datalist_remove_no_notify(&list, "three");
    g_print("del_data->id: %d, del_data->name: %s \n", del_data->id, del_data->name);
    _datalist_id_destroy_func(del_data);

    g_print("clear datalist \n");
    g_datalist_clear (&list);
}

int main (int argc, char** argv)
{
    g_datalist_id_test();

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_datalist_delete
destroy name:102!
del_data->id: 103, del_data->name: name:103
destroy name:103!
clear datalist
destroy name:101!
destroy name:104!
数据列表标志

不使用额外空间的情况下即可保存数据列表的标志值。除非运行环境的内存空间非常小,否则一般不会用到。GObject用了这个特性。

g_datalist_set_flags 
g_datalist_unset_flags 
g_datalist_get_flags 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值