删除Vala中GLib.Tree元素时出现无效指针问题
解决
free(): invalid pointer错误的分析与修复 先直接点出你代码里触发错误的核心问题:给GLib的Tree对象传了完全不匹配的销毁函数。
问题拆解
你初始化mainTree时写了这段代码:
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free, free);
这里的第三个参数free是用来销毁Tree的value——也就是内部嵌套的Tree<int, string>对象的,但Tree是GLib的引用计数型对象,它的内存管理靠引用计数机制,根本不能用free直接释放。free只能用来销毁手动通过malloc/g_malloc分配的内存,直接用它处理GLib对象会破坏内存结构,触发free(): invalid pointer这类内存错误。
再加上你的mainTree是全局变量,程序退出时会自动触发它的销毁逻辑,错误的销毁函数这时候就会直接引发崩溃。
修复步骤
替换错误的销毁函数:
- 对于字符串类型的key:如果你的key是动态分配的(比如用
g_strdup创建),用g_free作为销毁函数;如果是字符串字面量(比如"test_key"),直接传null(因为字面量存在只读内存区,不能被free)。 - 对于value(嵌套的
Tree<int, string>):必须用Tree.unref作为销毁函数,GLib对象需要通过减少引用计数来完成销毁。
- 对于字符串类型的key:如果你的key是动态分配的(比如用
修正初始化与使用逻辑:
还要确保内部的Tree<int, string>也设置了正确的销毁函数,避免嵌套层的内存问题。
修正后的示例代码
using GLib; using GLib.Random; // 全局变量 Tree<string, Tree<int, string> > mainTree; // 补充你未完整给出的比较函数 int mainTreeCompareDataFunction (string a, string b) { return strcmp(a, b); } public static int main (string[] args) { // 初始化随机种子 Random.set_seed ((uint32) get_monotonic_time()); // 修正销毁函数:key用g_free(对应动态分配的字符串),value用Tree.unref mainTree = new Tree<string, Tree<int, string> >.full ( mainTreeCompareDataFunction, (Func) g_free, (Func) Tree.unref ); // 随机次数循环(补全你未写完的代码) for (int i = 0; i < int_range (1000, 10001); i++) { // 创建动态分配的key,对应g_free销毁函数 string outerKey = g_strdup ("group_%d".printf(i)); // 初始化内部Tree,设置正确的销毁函数 Tree<int, string> innerTree = new Tree<int, string>.full ( (int a, int b) => a - b, null, // int类型key无需销毁 (Func) g_free // 动态分配的string value用g_free销毁 ); innerTree.insert(i, g_strdup ("item_%d".printf(i))); mainTree.insert(outerKey, innerTree); } return 0; }
额外提醒
所有GLib的引用计数对象(比如Tree、HashTable、各类Object子类),都必须用unref来完成销毁,绝对不能用free,这是GLib内存管理的基本规则,搞混就很容易触发内存错误。
内容的提问来源于stack exchange,提问作者g_l
相关产品推荐
相关产品推荐

