在Vala中删除GLib.Tree元素时指针无效

问题描述 投票:1回答:2

此代码导致以下错误

free(): invalid pointer

Online example

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值的destroy函数,则不会发生崩溃,但如果我要重用mainTree变量,则会产生内存泄漏。

有没有办法清空树并释放内存?

memory-management glib vala
2个回答
1
投票

您可以编写一个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类,因为难以正确地进行内存管理。你应该考虑使用Gee.TreeMap代替。


0
投票

找到了做手动内存管理的解决方案。首先,使嵌套树成为指针。其次,将null传递给参数,以指定释放嵌套树的函数。第三,将null传递给参数,以指定释放嵌套树的int键的函数。最后,在清空主树时,使用delete关键字减少对嵌套树的引用。

由于delete的手动调用在此代码中对嵌套树的引用将降为0,这里特别调用Vala生成的C代码中的g_tree_unref,嵌套树的所有键和值都将被销毁,并且所有内存都由树分配被释放。这样就不会再发生无效的指针错误,也没有内存泄漏。

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);
}

资料来源:

© www.soinside.com 2019 - 2024. All rights reserved.