在 Vala 中删除 GLib.Tree 个元素时指针无效
Invalid pointer when deleting GLib.Tree elements in Vala
此代码导致以下错误
free(): invalid pointer
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string> > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free, free);
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string> treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, free, free);
// Insert random content into treeToNest
treeToNest.insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
mainTree.remove (mainTreeKey); // This line causes a free(): invalid pointer error
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
我怀疑是因为树里面有一个嵌套的GLib.Tree
,而free()
不能用在那些对象上。如果我使用 null
而不是 mainTree
值的销毁函数,则不会发生崩溃,但如果我要重用 mainTree
变量,则会产生内存泄漏。
有没有办法清空树并释放内存?
找到解决方案,即手动内存管理。首先,将嵌套树设为 pointer。其次,将 null
传递给用于指定释放嵌套树的函数的参数。第三,将 null
传递给参数以指定用于释放嵌套树的 int
键的函数。最后,在清空主树时,使用 delete
关键字递减对嵌套树的引用。
因为这里特调用g_tree_unref
的delete
手动调用,这段代码中嵌套树的引用会降为0 Vala 生成的 C 代码,嵌套树的所有键和值都被销毁,树分配的所有内存都被释放。这样就不会再发生无效指针错误,也不会发生内存泄漏。
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string>* > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free, null);
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string>* treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, null, free);
// Insert random content into treeToNest
treeToNest->insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
delete mainTree.lookup (mainTreeKey);
mainTree.remove (mainTreeKey);
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
来源:
您可以编写一个 lambda,使用所有权转移删除子树。
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free,
(data) => {
var tree = (Tree<string, Tree<int, string>>) data;
// Ownership is transfered to this local var which calls unref when it goes out of scope
var tree2 = (owned) tree;
});
完整代码如下:
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string> > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free,
(data) => {
var tree = (Tree<string, Tree<int, string>>) data;
// Ownership is transfered to this local var which calls unref when it goes out of scope
var tree2 = (owned) tree;
});
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string> treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, null, free);
// Insert random content into treeToNest
treeToNest.insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
mainTree.remove (mainTreeKey);
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
我会避免在 Vala 中使用 GLib.Tree class,因为很难正确地进行内存管理。您应该考虑改用 Gee.TreeMap
。
此代码导致以下错误
free(): invalid pointer
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string> > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free, free);
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string> treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, free, free);
// Insert random content into treeToNest
treeToNest.insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
mainTree.remove (mainTreeKey); // This line causes a free(): invalid pointer error
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
我怀疑是因为树里面有一个嵌套的GLib.Tree
,而free()
不能用在那些对象上。如果我使用 null
而不是 mainTree
值的销毁函数,则不会发生崩溃,但如果我要重用 mainTree
变量,则会产生内存泄漏。
有没有办法清空树并释放内存?
找到解决方案,即手动内存管理。首先,将嵌套树设为 pointer。其次,将 null
传递给用于指定释放嵌套树的函数的参数。第三,将 null
传递给参数以指定用于释放嵌套树的 int
键的函数。最后,在清空主树时,使用 delete
关键字递减对嵌套树的引用。
因为这里特调用g_tree_unref
的delete
手动调用,这段代码中嵌套树的引用会降为0 Vala 生成的 C 代码,嵌套树的所有键和值都被销毁,树分配的所有内存都被释放。这样就不会再发生无效指针错误,也不会发生内存泄漏。
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string>* > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free, null);
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string>* treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, null, free);
// Insert random content into treeToNest
treeToNest->insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
delete mainTree.lookup (mainTreeKey);
mainTree.remove (mainTreeKey);
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
来源:
您可以编写一个 lambda,使用所有权转移删除子树。
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free,
(data) => {
var tree = (Tree<string, Tree<int, string>>) data;
// Ownership is transfered to this local var which calls unref when it goes out of scope
var tree2 = (owned) tree;
});
完整代码如下:
using GLib;
using GLib.Random;
// Global variable
Tree<string, Tree<int, string> > mainTree;
public static int main (string[] args) {
// Initiate random seed
Random.set_seed ((uint32) get_monotonic_time());
// mainTree initialization
mainTree = new Tree<string, Tree<int, string> >.full (mainTreeCompareDataFunction, free,
(data) => {
var tree = (Tree<string, Tree<int, string>>) data;
// Ownership is transfered to this local var which calls unref when it goes out of scope
var tree2 = (owned) tree;
});
// Random sized for loop
for (int i = 0; i < int_range (1000, 10001); i++) {
// If a condition is met (i is even)
if (i % 2 == 0) {
// Create a Tree to nest onto mainTree
Tree<int, string> treeToNest = new Tree<int, string>.full (treeToNestCompareDataFunction, null, free);
// Insert random content into treeToNest
treeToNest.insert (int_range (0, 101), randomString ());
// Insert the tree onto mainTree
mainTree.insert (randomString (), treeToNest);
}
}
// Empty the tree
mainTree.@foreach ((mainTreeKey, mainTreeValue) => {
mainTree.remove (mainTreeKey);
return false;
});
return 0;
}
public string randomString () {
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
string stringToReturn = "";
// Create a random 8 character string
for (int i = 0; i < 8; i++) {
stringToReturn += charset[int_range (0, charset.length)].to_string ();
}
return stringToReturn;
}
public int treeToNestCompareDataFunction (int a, int b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
public int mainTreeCompareDataFunction (string a, string b) {
return strcmp (a, b);
}
我会避免在 Vala 中使用 GLib.Tree class,因为很难正确地进行内存管理。您应该考虑改用 Gee.TreeMap
。