概述
简介
(本段内容翻译自官方文档)
数据集将数据元素组与特定的内存位置相关联。如果您需要将数据与从外部库返回的结构相关联,这些非常有用。由于您无法修改结构,因此您可以将其在内存中的位置用作数据集的键,您可以在其中将任意数量的数据元素与其关联。
大多数数据集函数有两种形式。第一种形式使用字符串来标识与位置关联的数据元素。第二种形式使用 GQuark 标识符,这些标识符是通过调用g_quark_from_string()或g_quark_from_static_string()创建的。第二种形式更快,因为它不需要在 GQuark 标识符的哈希表中查找字符串。
- 没有创建数据集的功能。只要您向其中添加元素,它就会自动创建。
- 要将数据元素添加到数据集,请使用 g_dataset_id_set_data()、g_dataset_id_set_data_full()、g_dataset_set_data() 和 g_dataset_set_data_full()。
- 要从数据集中获取数据元素,请使用 g_dataset_id_get_data()和 g_dataset_get_data()。
- 要遍历数据集中的所有数据元素,请使用 g_dataset_foreach()非线程安全)。
- 要从数据集中删除数据元素,请使用 g_dataset_id_remove_data()和g_dataset_remove_data()。
- 要销毁数据集,请使用 g_dataset_destroy()。
数据结构
数据集无固定的数据结构,任意指针都可被视作一个数据集。
函数列表
#define g_dataset_id_set_data()
void g_dataset_id_set_data_full ()
gpointer g_dataset_id_get_data ()
#define g_dataset_id_remove_data()
gpointer g_dataset_id_remove_no_notify ()
#define g_dataset_set_data()
#define g_dataset_set_data_full()
#define g_dataset_get_data()
#define g_dataset_remove_data()
#define g_dataset_remove_no_notify()
void g_dataset_foreach ()
void g_dataset_destroy ()
函数功能分类
dataset和datalist非常相似,其功能函数也可以分为分为两大类。
- g_dataset_id_xxx:将一个GQuark与一个任意元素数据相关联
- g_dataset_xxx:将一个字符串与一个任意元素数据相关联
插入元素
g_dataset_id_set_data()
g_dataset_id_set_data_full ()
g_dataset_set_data()
g_dataset_set_data_full()
移除元素
g_dataset_id_remove_data()
g_dataset_id_remove_no_notify ()
g_dataset_remove_data()
g_dataset_remove_no_notify()
遍历
g_dataset_foreach
销毁
g_dataset_destroy
函数功能说明及综合演示
创建
dataset没有创建函数,可以定义一个任意类型的变量作为dataset。
当添加元素时,dataset会被自动创建。
插入元素
set_data和set_data_full均可插入元素
g_dataset_id_set_xxx用GQuark作为索引
g_dataset_id_set_xxx用字符串作为索引
带full的函数,包含一个数据自定义释放函数变量,可以释放自定义的函数
如果插入的key已经存在,且存在元素自定义释放函数,该key对应的元素会被释放函数释放,新的元素将被插入。这一点与datalist特性相同。
g_dataset_id_set_data()
g_dataset_id_set_data_full ()
g_dataset_set_data()
g_dataset_set_data_full()
获取元素
g_dataset_id_get_data通过GQuark获取其对应的值。
g_dataset_get_data通过字符串获取其对应的值。
gpointer g_dataset_id_get_data ()
#define g_dataset_get_data(l, k)
下面程序,将一个字符串与一个结构体相关联,组成数据集,展示了使用g_dataset_id_set_data_full函数向字符集插入元素及替换原有元素,使用g_dataset_id_get_data获取数据集中的元素。
示例代码如下:
源码见glib_examplesglib_datasetglib_dataset_set_get_data
#include <glib.h>
typedef struct my_data_tag {
gint id;
gchar *name;
}my_data_t;
static void _dataset_foreach_func(GQuark key_id, gpointer data, gpointer user_data)
{
my_data_t *p = (my_data_t *)data;
g_print("[foreach] key:%s, id: %d, name: %s, user_data: %s n",
g_quark_to_string(key_id), p->id, p->name, (gchar *)user_data);
}
static void _dataset_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 glib_dataset_set_get_test (void)
{
gpointer location = (gpointer)glib_dataset_set_get_test;
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;
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_dataset_id_set_data_full(location, g_quark_from_string ("one"), data1, _dataset_id_destroy_func);
g_dataset_id_set_data_full(location, g_quark_from_string ("two"), data2, _dataset_id_destroy_func);
g_dataset_id_set_data_full(location, g_quark_from_string ("three"), data3, _dataset_id_destroy_func);
g_dataset_foreach(location, _dataset_foreach_func, (gpointer)"foreach");
g_print("before set_data_full: two n");
g_dataset_id_set_data_full(location, g_quark_from_string ("two"), data4, _dataset_id_destroy_func);
g_print("after set_data_full: two n");
ret = g_dataset_id_get_data (location, 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_dataset_destroy (location);
}
gint main (gint argc, gchar** argv)
{
glib_dataset_set_get_test();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_dataset_set_get_data
data2->id(0x1e4ee70): 102
data2->name(0x1e4ee90): name:102
[foreach] key:one, id: 101, name: name:101, user_data: foreach
[foreach] key:two, id: 102, name: name:102, user_data: foreach
[foreach] key:three, id: 103, name: name:103, user_data: foreach
before set_data_full: two
destroy name:102!
after set_data_full: two
ret->id(0x1e4eef0): 104
ret->name(0x1e4ef10): name:104
destroy name:101!
destroy name:104!
destroy name:103!
移除元素
no_notify意思是删除元素不自动释放,返回值为已从dataset删除的元素的指针地址,调用者需自行释放该内存。
g_dataset_id_remove_data()
g_dataset_id_remove_no_notify ()
g_dataset_remove_data()
g_dataset_remove_no_notify()
遍历
在进行数据集元素遍历时,需要提供一个遍历函数。
注意:本函数并非线程安全。
g_dataset_foreach ()
销毁
调用g_dataset_destroy函数时,若存在元素释放函数,则释放函数会被自动调用,若不存在元素释放函数且元素不需要被释放,g_dataset_destroy可以不调用。
当不存在元素释放函数且元素不需要被释放时,使用valgrind工具运行对比下面两个程序,可以看到无论是否调用g_dataset_destroy函数,都不会造成内存泄露。
g_dataset_destroy ()
调用释放函数
示例代码如下:
源码见glib_examplesglib_datasetglib_dataset_with_destroy
#include <glib.h>
typedef struct my_data_tag {
gint id;
gchar *name;
}my_data_t;
static void _dataset_foreach(GQuark key_id, gpointer data, gpointer user_data)
{
g_print("key:%s data: %s n", g_quark_to_string(key_id), (gchar *)data);
}
static void glib_dataset_test (void)
{
gpointer location = (gpointer)glib_dataset_test;
gpointer data1 = "test1";
gpointer data2 = "test2";
gpointer ret;
g_dataset_set_data (location, "key_test1", data1);
g_dataset_set_data (location, "key_test2", data2);
g_dataset_foreach(location, _dataset_foreach, location);
g_print("Call destroy function n");
g_dataset_destroy(location);
}
gint main (gint argc, gchar** argv)
{
glib_dataset_test();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_dataset_with_destroy
key:key_test1 data: test1
key:key_test2 data: test2
Call destroy function
内存泄露检查:
[root@centos7_6 build]# valgrind --tool=memcheck --leak-check=full ./glib_dataset_with_destroy
==9277== Memcheck, a memory error detector
==9277== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9277== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9277== Command: ./glib_dataset_with_destroy
==9277==
key:key_test1 data: test1
key:key_test2 data: test2
Call destroy function
==9277==
==9277== HEAP SUMMARY:
==9277== in use at exit: 23,062 bytes in 16 blocks
==9277== total heap usage: 40 allocs, 24 frees, 123,164 bytes allocated
==9277==
==9277== LEAK SUMMARY:
==9277== definitely lost: 0 bytes in 0 blocks
==9277== indirectly lost: 0 bytes in 0 blocks
==9277== possibly lost: 0 bytes in 0 blocks
==9277== still reachable: 23,062 bytes in 16 blocks
==9277== suppressed: 0 bytes in 0 blocks
==9277== Reachable blocks (those to which a pointer was found) are not shown.
==9277== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==9277==
==9277== For counts of detected and suppressed errors, rerun with: -v
==9277== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
不调用释放函数
示例代码如下:
源码见glib_examplesglib_datasetglib_dataset_without_destroy
#include <glib.h>
typedef struct my_data_tag {
gint id;
gchar *name;
}my_data_t;
static void _dataset_foreach(GQuark key_id, gpointer data, gpointer user_data)
{
g_print("key:%s data: %s n", g_quark_to_string(key_id), (gchar *)data);
}
static void glib_dataset_test (void)
{
gpointer location = (gpointer)glib_dataset_test;
gpointer data1 = "test1";
gpointer data2 = "test2";
gpointer ret;
g_dataset_set_data (location, "key_test1", data1);
g_dataset_set_data (location, "key_test2", data2);
g_dataset_foreach(location, _dataset_foreach, location);
g_print("Not call destroy function n");
//g_print("Call destroy function n");
//g_dataset_destroy(location);
}
gint main (gint argc, gchar** argv)
{
glib_dataset_test();
return 0;
}
运行结果:
[root@centos7_6 build]# ./glib_dataset_without_destroy
key:key_test1 data: test1
key:key_test2 data: test2
Not call destroy function
内存泄露检查:
[root@centos7_6 build]# valgrind --tool=memcheck --leak-check=full ./glib_dataset_without_destroy
==8979== Memcheck, a memory error detector
==8979== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8979== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8979== Command: ./glib_dataset_without_destroy
==8979==
key:key_test1 data: test1
key:key_test2 data: test2
Not call destroy function
==8979==
==8979== HEAP SUMMARY:
==8979== in use at exit: 23,134 bytes in 18 blocks
==8979== total heap usage: 40 allocs, 22 frees, 123,172 bytes allocated
==8979==
==8979== LEAK SUMMARY:
==8979== definitely lost: 0 bytes in 0 blocks
==8979== indirectly lost: 0 bytes in 0 blocks
==8979== possibly lost: 0 bytes in 0 blocks
==8979== still reachable: 23,134 bytes in 18 blocks
==8979== suppressed: 0 bytes in 0 blocks
==8979== Reachable blocks (those to which a pointer was found) are not shown.
==8979== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==8979==
==8979== For counts of detected and suppressed errors, rerun with: -v
==8979== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
上述对比运行结果可见,无论是否调用释放函数,均无内存泄露发生,因为整个过程数据集元素都是常量字符串,存储在内存的静态存储区,无需手动释放内存。而对于自定义的数据结构,由于有在堆上进行内存申请,必须调用释放函数,否则会造成内存泄露。
最后
以上就是苹果皮带为你收集整理的4_14_GLib库入门与实践_数据集的全部内容,希望文章能够帮你解决4_14_GLib库入门与实践_数据集所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复