概述
简介
(本段内容翻译自官方文档)
数据列表提供任意数据元素的列表,可以使用字符串或与字符串的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_examplesglib_datalistglib_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_examplesglib_datalistglib_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_examplesglib_datalistglib_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_examplesglib_datalistglib_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!
上述示例程序有三个需要注意的地方:
- old_data必须是已经存在于列表中的一个元素,手动构造出的,即使值完全一致,也不可以。
- 被替换的元素不会被自动释放,需要手动调用其释放函数。
- 新插入的元素,自带一个释放函数,可以和之前的释放函数不一样。列表清空或销毁时,会自动调用对应的元素释放函数。
一般来说,数组,链表,队列,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_examplesglib_datalistglib_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
最后
以上就是顺心云朵为你收集整理的4_13_GLib库入门与实践_数据列表的全部内容,希望文章能够帮你解决4_13_GLib库入门与实践_数据列表所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复