简介
(本段内容翻译自官方文档)
数据集将数据元素组与特定的内存位置相关联。如果您需要将数据与从外部库返回的结构相关联,这些非常有用。由于您无法修改结构,因此您可以将其在内存中的位置用作数据集的键,您可以在其中将任意数量的数据元素与其关联。
大多数数据集函数有两种形式。第一种形式使用字符串来标识与位置关联的数据元素。第二种形式使用 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()。
数据结构
数据集无固定的数据结构,任意指针都可被视作一个数据集。
函数列表
1
2
3
4
5
6
7
8
9
10
11
12
13#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:将一个字符串与一个任意元素数据相关联
插入元素
1
2
3
4
5g_dataset_id_set_data() g_dataset_id_set_data_full () g_dataset_set_data() g_dataset_set_data_full()
移除元素
1
2
3
4
5g_dataset_id_remove_data() g_dataset_id_remove_no_notify () g_dataset_remove_data() g_dataset_remove_no_notify()
遍历
1
2g_dataset_foreach
销毁
1
2g_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特性相同。
1
2
3
4
5g_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通过字符串获取其对应的值。
1
2
3gpointer 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79#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; }
运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15[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删除的元素的指针地址,调用者需自行释放该内存。
1
2
3
4
5g_dataset_id_remove_data() g_dataset_id_remove_no_notify () g_dataset_remove_data() g_dataset_remove_no_notify()
遍历
在进行数据集元素遍历时,需要提供一个遍历函数。
注意:本函数并非线程安全。
1
2g_dataset_foreach ()
销毁
调用g_dataset_destroy函数时,若存在元素释放函数,则释放函数会被自动调用,若不存在元素释放函数且元素不需要被释放,g_dataset_destroy可以不调用。
当不存在元素释放函数且元素不需要被释放时,使用valgrind工具运行对比下面两个程序,可以看到无论是否调用g_dataset_destroy函数,都不会造成内存泄露。
1
2g_dataset_destroy ()
调用释放函数
示例代码如下:
源码见glib_examplesglib_datasetglib_dataset_with_destroy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#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; }
运行结果:
1
2
3
4
5[root@centos7_6 build]# ./glib_dataset_with_destroy key:key_test1 data: test1 key:key_test2 data: test2 Call destroy function
内存泄露检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26[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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#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; }
运行结果:
1
2
3
4
5[root@centos7_6 build]# ./glib_dataset_without_destroy key:key_test1 data: test1 key:key_test2 data: test2 Not call destroy function
内存泄露检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26[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库入门与实践_数据集内容请搜索靠谱客的其他文章。
发表评论 取消回复