【问题标题】:Trie double free or corruption in destructor在析构函数中尝试双重释放或损坏
【发布时间】:2015-11-15 16:48:11
【问题描述】:

我正在用 C++ 编写前缀树类。树中的每个节点都有一个长度为 27 的数组Node*。这些是用来存放字母和空格的。我通过将所有字母转换为小写并将所有符号转换为空格来清理树的任何输入。在析构函数中,我调用了一个名为 clear 的函数,它接受一个节点(首先是根节点)。在编写单元测试时,它只会成功通过一个测试,而在 Prefix 类上调用析构函数的第二个测试失败并出现双重释放或损坏错误。我之前遇到过这个问题并且能够检测到问题并解决它,但是我无法弄清楚是什么原因造成的,这里有一些代码:

节点结构:

const unsigned int B_FACTOR = 27;  // a..z plus space

struct Node_t {
    bool word;
    Node_t *links[B_FACTOR];
    Node_t(): word(false) {}
};

插入(公共和私有):

bool Prefix::insert(string thing) {
    sanitize(thing);
    if(!root) root = new Node_t();
    if(thing == "") return true;
    insertPrivate(thing, root);
    return true;
}

void Prefix::insertPrivate(string input, Node_t *node) {
    if(input == "") {
        node->word = true;
        return;
    }
    int idx = (int(input[0])-97) >= 0 ? (int(input[0])-97) : 26;
    if(!node->links[idx]) node->links[idx] = new Node_t();
    insertPrivate(input.substr(1, input.length()), node->links[idx]);
}

析构函数:

Prefix::~Prefix() {
    clear(root);
}

清除:

void Prefix::clear(Node_t *node) {
    if(!node) return;
    cout << "On Node " << endl;
    for (int i = 0; i < 26; ++i) {
        clear(node->links[i]);
    }
    delete node;
}

单元测试:

void testInsert0() {
    cout << "testInsert0" << endl;
    Prefix a;
    a.insert("a");
    TS_ASSERT(a.isStored("a"));
}

void testInsert1() {
    cout << "testInsert1" << endl;
    Prefix b;
    b.insert("dd");
    TS_ASSERT_EQUALS(b.isStored("d"), false);
}

void testInsert2() {
    cout << "testInsert2" << endl;
    Prefix a;
    a.insert("abcdef");
    TS_ASSERT(!a.isStored("abcd"));
}

进行测试的输出如下:

Running cxxtest tests (4 tests).testInsert0
On Node 
On Node 
.testInsert1
Post test
On Node 
On Node 
On Node 
On Node 
On Node 
*** Error in `./testrunner': double free or corruption (out): 0x00000000019652a0 ***
make: *** [test] Aborted (core dumped)

当我注释掉调用 clear 函数的析构函数中的代码时,一切正常(当然有很多内存错误),但是当析构函数处于活动状态时,它无法通过 2 个完整的单元测试来锻炼其能力.

【问题讨论】:

    标签: c++ oop data-structures destructor prefix


    【解决方案1】:

    这可能是并非所有变量都已初始化的情况,这会导致对delete 的虚假调用。确保 Node_t 结构的每个链接在使用之前都设置为 nullptr

    还可以查看Valgrind,它会在虚拟机中运行您的程序以检查常见的内存问题 - 它对于这类事情非常有用。

    【讨论】:

    • 我很困惑,如果我创建一个新的 Prefix 指针并且不删除它,那将如何改变析构函数的作用?
    • 另外我不相信根指针在堆栈上,因为在insert 中,我正在检查根是否存在,如果不存在,我用new 分配一个新指针
    • 您是否在 Prefix 的构造函数中将根元素设置为 nullptr
    • 是的,我将其设置为 NULL,因为对于此作业,自动评分器不包括 -std=c++0x 以支持 nullptr,但我设置为 NULL
    • 好电话,我刚刚做了Node_t *links[B_FACTOR] = {NULL},非常感谢您。我假设数组中的值具有非常疯狂的值,但从技术上讲不是NULL,所以很清楚不知道何时停止,它会出现段错误或双重释放。谢谢!
    猜你喜欢
    • 2014-06-26
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多