【问题标题】:Ilogical 'double free or corruption (fasttop)' error不合逻辑的“双重释放或损坏(fasttop)”错误
【发布时间】:2020-05-12 10:44:08
【问题描述】:

我正在做一些二叉搜索树作业,出现了这个“双重释放或损坏(fasttop)”错误。

*** Error in `./bin/Main': double free or corruption (fasttop): 0x0000000000c25c20 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f9546af77e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f9546b0037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f9546b0453c]
./bin/Main[0x400f21]
./bin/Main[0x400e1b]
./bin/Main[0x400d8c]
./bin/Main[0x400cc0]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f9546aa0830]
./bin/Main[0x400b69]
======= Memory map: ========
00400000-00402000 r-xp 00000000 00:00 6594                       /home/alu0101228587/c++_projects/bin/Main
00402000-00403000 r-xp 00002000 00:00 6594                       /home/alu0101228587/c++_projects/bin/Main
00602000-00603000 r--p 00002000 00:00 6594                       /home/alu0101228587/c++_projects/bin/Main
00603000-00604000 rw-p 00003000 00:00 6594                       /home/alu0101228587/c++_projects/bin/Main
00c14000-00c46000 rw-p 00000000 00:00 0                          [heap]
7f9540000000-7f9540021000 rw-p 00000000 00:00 0
7f9540021000-7f9544000000 ---p 00000000 00:00 0
7f9546770000-7f9546878000 r-xp 00000000 00:00 811272             /lib/x86_64-linux-gnu/libm-2.23.so
7f9546878000-7f954687a000 ---p 00108000 00:00 811272             /lib/x86_64-linux-gnu/libm-2.23.so
7f954687a000-7f9546a77000 ---p 0000010a 00:00 811272             /lib/x86_64-linux-gnu/libm-2.23.so
7f9546a77000-7f9546a78000 r--p 00107000 00:00 811272             /lib/x86_64-linux-gnu/libm-2.23.so
7f9546a78000-7f9546a79000 rw-p 00108000 00:00 811272             /lib/x86_64-linux-gnu/libm-2.23.so
7f9546a80000-7f9546c40000 r-xp 00000000 00:00 808634             /lib/x86_64-linux-gnu/libc-2.23.so
7f9546c40000-7f9546c49000 ---p 001c0000 00:00 808634             /lib/x86_64-linux-gnu/libc-2.23.so
7f9546c49000-7f9546e40000 ---p 000001c9 00:00 808634             /lib/x86_64-linux-gnu/libc-2.23.so
7f9546e40000-7f9546e44000 r--p 001c0000 00:00 808634             /lib/x86_64-linux-gnu/libc-2.23.so
7f9546e44000-7f9546e46000 rw-p 001c4000 00:00 808634             /lib/x86_64-linux-gnu/libc-2.23.so
7f9546e46000-7f9546e4a000 rw-p 00000000 00:00 0
7f9546e50000-7f9546e66000 r-xp 00000000 00:00 808707             /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9546e66000-7f9547065000 ---p 00000016 00:00 808707             /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9547065000-7f9547066000 rw-p 00015000 00:00 808707             /lib/x86_64-linux-gnu/libgcc_s.so.1
7f9547070000-7f95471e2000 r-xp 00000000 00:00 840863             /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f95471e2000-7f95471ef000 ---p 00172000 00:00 840863             /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f95471ef000-7f95473e2000 ---p 0000017f 00:00 840863             /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f95473e2000-7f95473ec000 r--p 00172000 00:00 840863             /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f95473ec000-7f95473ee000 rw-p 0017c000 00:00 840863             /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f95473ee000-7f95473f2000 rw-p 00000000 00:00 0
7f9547400000-7f9547425000 r-xp 00000000 00:00 808510             /lib/x86_64-linux-gnu/ld-2.23.so
7f9547425000-7f9547426000 r-xp 00025000 00:00 808510             /lib/x86_64-linux-gnu/ld-2.23.so
7f9547625000-7f9547626000 r--p 00025000 00:00 808510             /lib/x86_64-linux-gnu/ld-2.23.so
7f9547626000-7f9547627000 rw-p 00026000 00:00 808510             /lib/x86_64-linux-gnu/ld-2.23.so
7f9547627000-7f9547628000 rw-p 00000000 00:00 0
7f9547750000-7f9547751000 rw-p 00000000 00:00 0
7f9547760000-7f9547761000 rw-p 00000000 00:00 0
7f9547770000-7f9547772000 rw-p 00000000 00:00 0
7f9547780000-7f9547781000 rw-p 00000000 00:00 0
7f9547790000-7f9547791000 rw-p 00000000 00:00 0
7f95477a0000-7f95477a1000 rw-p 00000000 00:00 0
7fffe8039000-7fffe8839000 rw-p 00000000 00:00 0                  [stack]
7fffe8f7c000-7fffe8f7d000 r-xp 00000000 00:00 0                  [vdso]

这是主程序:

#include "bsearch_tree_s.cpp"
#include "../include/dni.hpp"

int main(void)
{   
  bsearch_tree_s<int> tree;

  tree.insert(20);
  tree.insert(6);
  tree.insert(1);
  tree.insert(90);
  tree.insert(23);

  tree.write(cout);

  return 0;
}

这很简单,因为我只是想测试我的课程。

问题是,通过注释主程序中的行,我注意到产生错误的方法是 btree_c::insert(int)。

b_search_tree_c 类(子)头文件:

#ifndef __BSEARCH_TREE_S__
#define __BSEARCH_TREE_S__

#include "../src/btree_c.cpp"

using namespace std;

template <typename Clave = int>
class bsearch_tree_s: public btree_c<Clave>
{   public:
        bsearch_tree_s(void);

        bsearch_tree_s(bnode_c<Clave>*);

        ~bsearch_tree_s(void);

        ostream& write(ostream&) const;
};

#endif

bsearch_tree_c 类(子)cpp 文件:

#include "../include/bsearch_tree_s.hpp"

template <typename Clave>
bsearch_tree_s<Clave>::bsearch_tree_s(void):
btree_c<Clave>::btree_c() {}

template <typename Clave>
bsearch_tree_s<Clave>::~bsearch_tree_s(void)
{ btree_c<Clave>::~btree_c(); }

template <typename Clave>
ostream& bsearch_tree_s<Clave>::write(ostream& os) const
{   
  unsigned int root_level = 0;

  return btree_c<Clave>::print(os, btree_c<Clave>::root_, root_level);
}

btree_c 类(父)头文件:

#ifndef __BTREE_C__
#define __BTREE_C__

#include <iostream>
#include <cstdio>
#include <cassert>

#include "../src/bnode_c.cpp"

using namespace std;

template <typename Clave = int>
class btree_c
{   
    protected:
        int depth_;

        unsigned int size_;

        bnode_c<Clave>* root_;

    public:
        btree_c(void);

        btree_c(bnode_c<Clave>*);

        ~btree_c(void);

        void cut(bnode_c<Clave>*);

        bool is_empty(void) const;

        ostream& print(ostream&, bnode_c<Clave>*, unsigned int) const;

        void insert(const Clave);

        bnode_c<Clave>* get_root(void) const;

    private:
        void insert_branch(const Clave, bnode_c<Clave>*&);
};

#endif

btree_c 类(父)cpp 文件:

#include "../include/btree_c.hpp"

using namespace std;

template <typename Clave>
btree_c<Clave>::btree_c(void):
depth_(-1),
size_(0),
root_(NULL) {}


template <typename Clave>
btree_c<Clave>::btree_c(bnode_c<Clave>* root):
depth_(0),
size_(1),
root_(root) {}


template <typename Clave>
btree_c<Clave>::~btree_c(void) { cut(root_); }


template <typename Clave>
void btree_c<Clave>::cut(bnode_c<Clave>* node)
{   if (node == NULL) return;

    cut(node->left_);
    cut(node->right_);

    delete node;
    node = NULL;
}

template <typename Clave>
ostream& btree_c<Clave>::print(ostream& os, bnode_c<Clave>* node, unsigned int level) const
{   if (node == NULL) return os;

    else
    {   
        os << "Level " << level << ": [" << node->get_data() << "]  " << endl;

        level++;

        print(os, node->left_, level);
        print(os, node->right_, level);

        return os;
    }
}

template <typename Clave>
void btree_c<Clave>::insert(const Clave clave)
{   if (root_ == NULL)
      root_ = new bnode_c<Clave>(clave);
    else 
      insert_branch(clave, root_);

    size_++;
}

template <typename Clave>
void btree_c<Clave>::insert_branch(const Clave clave, bnode_c<Clave>*& node)
{   if (node == NULL)
        node = new bnode_c<Clave>(clave);

    else if (clave < node->get_data())
        insert_branch(clave, node->left_);

    else insert_branch(clave, node->right_);
}

bnode_c 头文件:

#ifndef __BNODE_C__
#define __BNODE_C__

#include <iostream>
#include <cstdio>
#include <cassert>

using namespace std;

template <typename TDato = int>
class bnode_c
{   private:
        TDato data_;

    public:
        bnode_c<TDato>* left_;

        bnode_c<TDato>* right_;

        bnode_c(void);

        bnode_c(const TDato&);

        ~bnode_c(void);

        TDato& get_data(void);
};

#endif

bnode_c 类 cpp 文件:

#include "../include/bnode_c.hpp"

using namespace std;

template <typename TDato>
bnode_c<TDato>::bnode_c(void):
    left_(NULL),
    right_(NULL),
    data_(NULL) {}

template <typename TDato>
bnode_c<TDato>::bnode_c(const TDato& dat):
    left_(NULL),
    right_(NULL),
    data_(dat) {}


template <typename TDato>
bnode_c<TDato>::~bnode_c(void)
{   left_ = NULL;

    right_ = NULL;
}

template <typename TDato>
TDato& bnode_c<TDato>::get_data(void) { return data_;}

我不知道如何解决这个问题,因为我的代码中从来没有出现过这个错误,所以我需要你的帮助。

提前致谢。

【问题讨论】:

  • 此问题中显示的代码不符合 stackoverflow.com 对minimal reproducible example 的要求。这意味着这里的任何人都不太可能最终回答这个问题。但最多只能猜测。这个问题必须是edited 以显示一个最小示例,不超过一两页代码(“最小”部分),其他人都可以剪切/粘贴、编译、运行和重现所描述的问题( “可重现”部分)完全如图所示(这包括任何辅助信息,例如程序的输入)。请参阅How to Ask 了解更多信息。
  • @SamVarshavchik 我认为我发布的代码已经足够了。你觉得我应该补充什么?
  • 我猜错误出在 bsearch_tree 析构函数中:我在插入代码中没有看到任何显式或隐式删除。
  • Sam 要求我们可以实际编译和运行以重现错误的代码,而不仅仅是要读取的片段,当有一些不明显或棘手的事情时,这可能很有用。不过,我很惊讶您没有得到一个可用的调用堆栈并出现错误:您是否使用调试符号编译它(例如 -g 与 gcc)?
  • 不,发布所有内容都太多了,是的:我认为您的想法是您将其编辑到仍然会重现问题的最少代码量,例如从没有被调用的类中删除大部分方法,并且通常创建像这样最简单的示例将帮助您找到问题。 (如果你不发布这样一个最小的完整示例,你会发现很多人会感到不安,即使已经有足够的信息来回答这个问题,这是愚蠢和错误的,但你去吧。)

标签: c++ binary-tree binary-search-tree


【解决方案1】:

您的 bsearch_tree_s 析构函数正在显式调用其超类析构函数:

template <typename Clave>
bsearch_tree_s<Clave>::~bsearch_tree_s(void)
{ btree_c<Clave>::~btree_c(); }

这是错误的:它不需要这样做,无论如何它都会被自动调用,结果是 ~btree_c() 将尝试删除它的 root_ 节点两次,因此出现错误。可能值得暂时将跟踪输出添加到 ~bsearch_tree_s 和 ~btree_c 以查看此内容。

删除cut 中的node 指针后,您确实会清除它,但由于这是按值传递而不是引用,因此不会更改root_ 成员。另一种解决方法是在您拥有 cut 之后在 ~btree_c() 中设置 root_ = NULL;

【讨论】:

  • 是的,一旦我在~bsearch_tree_s() 中评论了对~btree_c() 的调用,一切正常。我还删除了~btree_c() 中的node = NULL 行,因为@Surt 建议它没有用。
  • 另外,这也适用于构造函数吗?
  • 您可以从初始化列表中调用超类构造函数,但除非您想传递参数,否则您不需要这样做——它将自动调用。
【解决方案2】:
template <typename Clave>
void btree_c<Clave>::cut(bnode_c<Clave>* node)
{   if (node == NULL) return;

    cut(node->left_);
    cut(node->right_);

    delete node;
    node = NULL; <---- this doesn't do anything
}

它需要一个附加的 & 来做某事。

void btree_c<Clave>::cut(bnode_c<Clave>*& node)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多