【问题标题】:Binary search tree destructor: free() invalid pointer二叉搜索树析构函数:free() 无效指针
【发布时间】:2015-11-24 19:25:48
【问题描述】:

对于我当前的编程任务,我必须构建一个二叉搜索树,并使用它按字母顺序从文件中插入单词,以制作索引列表。程序完整,输出正确;该程序的主要部分完美运行。但是当程序完成并调用析构函数时,它会因error in ./concordancebst : free(): invalid pointer 而崩溃。我不知道问题出在哪里,我的析构函数看起来可以工作,并且在线查看代码似乎也应该可以工作。我可能可以通过使用std::unique_ptr 来解决这个问题,但从程序范围的角度来看,这似乎有点矫枉过正(在我们没有涵盖智能指针的意义上也是矫枉过正,我们在课堂上所做的一切都涉及动态内存已通过手动分配/解除分配处理)。

BST.h

#ifndef BST_H
#define BST_H
#include <string>

class BST {
public:
   BST() { root = nullptr; }
   ~BST();

   void insert(const std::string word);
   int getCount(const std::string word);
   int length();

   friend std::ostream& operator << (std::ostream &out_s, BST b);
private:
   struct Node {
      std::string word;
      int count;
      Node *left;
      Node *right;
      Node() { word = ""; count = 0; left = nullptr; right = nullptr;}
      ~Node();
   };
   Node *root;

   void RInsert(Node* &t, std::string word);
   int countNodes(Node *p);
   void print(Node *p, std::ostream &out_s);
};
#endif

BST.cpp

#include "BST.h"
#include <string>
#include <iostream>
#include <iomanip>

BST::Node::~Node() {
   delete left;
   delete right;
}

BST::~BST() {
   delete root; 
}

int BST::countNodes(Node *p) {
   if(p == nullptr)
      return 0;
   else
      return countNodes(p->left) + countNodes(p->right) + 1;
}

int BST::getCount(const std::string word) {
   Node *p = root;
   while(true) {
      if(p == nullptr)
         return 0;
      else if(word.compare(p->word) < 0)
         p = p->left;
      else if(word.compare(p->word) == 0)
         return p->count;
      else
         p = p->right;
   }
}

int BST::length() {
   return countNodes(root);
}

void BST::RInsert(Node* &t, std::string word) {
   if(t == nullptr) {
      t = new Node;
      t->word = word;
      t->left = nullptr;
      t->right = nullptr;
      t->count++;
   }
   else if(word.compare(t->word) == 0)
      t->count++;
   else if(word.compare(t->word) < 0)
      RInsert(t->left, word);
   else //word.compare(t->word > 0)
      RInsert(t->right, word);
}

void BST::insert(const std::string word) {
   RInsert(root, word);
}

void BST::print(Node *p, std::ostream &out_s) {
   if(p != nullptr) {
      print(p->left, out_s);
      out_s << std::setw(13) << p->word << std::setw(10) << p->count <<  std::endl;
      print(p->right, out_s);
   }
}

std::ostream &operator << (std::ostream &out_s, BST b) {
   out_s << std::setw(13) << "Word" << std::setw(10) << "Count" << std::endl;
   out_s << "---------------------------------------------" << std::endl;
   b.print(b.root, out_s);
   out_s << "---------------------------------------------" << std::endl;
   out_s << "The file contains " << b.length() << " distinct words." << std::endl;

   return out_s;
}

【问题讨论】:

  • And where is your int main()? “主要”与“完成”一样。
  • 题外话:节省一点打字时间和一两个时钟周期。 Node() { word = ""; count = 0; left = nullptr; right = nullptr;} 可以是Node(): word(""), count(0), left(nullptr), right(nullptr){}
  • 您所说的错误,您提到 free 函数失败。我在您粘贴的代码 sn-p 中没有看到 free 函数调用。您确定要向我们展示相关代码吗?在旁注中,当内存由new 分配时,您是否有机会使用free 释放内存?
  • @AlgirdasPreidžius 好点值得探索,但在delete 的阴暗面深处,人们经常会找到free
  • MCVE 有两个很好的理由:它迫使提问者更深入地调查他们的代码和问题。通常情况下,构建最小案例会暴露错误并省去提出问题的麻烦。能够导出最少的代码是一项重要的调试技能,可能就在使用调试器之后。其次,MCVE 允许任何人将程序代码粘贴到他们选择的 IDE 中,并直接查看问题所在。它消除了复制提问者使用的测试用例所涉及的猜测,也消除了想知道错误是否在未显示的代码中所浪费的时间。

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


【解决方案1】:
std::ostream &operator << (std::ostream &out_s, BST b)
                                       Pass by value^. b is copied.

由于BST 没有复制构造函数,所以调用默认的复制构造函数并且不执行深度复制。 b 包含源 BST 的指针的副本,当 b 在从函数返回时被销毁时,它会将源的所有 Nodes 带入坟墓。

修复是双重的:

最直接的,通过引用传递。

std::ostream &operator << (std::ostream &out_s, BST & b)

间接地,此代码违反了Rule of ThreeBSTBST::Node 需要复制构造函数和赋值运算符才能安全使用。

编辑

一个最小的测试用例是这样的:

#include <iostream>
#include "BST.h"

int main()
{
    BST t;

    t.insert("A");

    std::cout << t << std::endl;
    return 0;
}

【讨论】:

  • 哦,现在我明白了实现复制构造函数是什么意思。现在我看到实际上需要它才能使代码按预期工作而不通过 b。我的教授从来没有谈论过三法则,所以我不知道,但从现在开始,我会确保遵守它。非常感谢!
  • 没问题。还要留意五法则(基本上是三法则,还有处理std::move 的额外方法)。更多精彩阅读:en.cppreference.com/w/cpp/language/rule_of_three
猜你喜欢
  • 2011-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多