2015-11-24 2 views
-1

Для моего текущего программирования я должен построить двоичное дерево поиска и использовать его для вставки слов из файла в алфавитном порядке, чтобы составить список соответствия. Программа завершена и выводится правильно; основная часть программы работает отлично. Но когда программа заканчивается и вызываются деструкторы, она вылетает с error in ./concordancebst : free(): invalid pointer. Я не понимаю, в чем проблема, мой деструктор выглядит так, как будто он работает, и глядя на код онлайн, кажется, что он тоже должен работать. Я мог бы обойти это, используя std::unique_ptr, но он, похоже, немного переборщил в смысле объема программы (также излишний в том смысле, что мы не охватили интеллектуальные указатели, все, что мы сделали в классе, включающем динамическую память был обработан посредством ручного распределения/освобождения).Двоичный древовидный древовидный поиск: free() недействительный указатель

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; 
} 
+1

[А где ваш ** 'INT основной()' **] (http://stackoverflow.com/help/mcve)? «основной», как в «полной». –

+0

Off topic: Сохраните немного ввода и часовой цикл или два. 'Node() {word =" "; count = 0; left = nullptr; right = nullptr;} 'может быть' Node(): word (""), count (0), left (nullptr), right (nullptr) {} ' – user4581301

+0

Ошибка, которую вы сказали, что у вас есть упоминания' свободный' функция неисправность. Я не вижу вызов функции 'free' в фрагменте кода, который вы вставили. Вы уверены, что показываете нам соответствующий код? С другой стороны, можете ли вы, случайно, освободить память «свободным», когда эта память была выделена «новым»? –

ответ

2
std::ostream &operator << (std::ostream &out_s, BST b) 
             Pass by value^. b is copied. 

Поскольку BST не имеет конструктор копирования, конструктор копирования по умолчанию вызывается и не выполняет глубокий копия. b содержит копии указателей источника BST, а когда b уничтожен при возврате из функции, он берет с собой все из источника Node с могилой.

затруднительные двояко:

Большинства непосредственно, проходят по ссылке.

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

Косвенно, этот код нарушает Rule of Three. BST и BST::Node нужны конструкторы копирования и операторы присваивания, которые будут использоваться безопасно.

Редактировать

Минимальный тестовый случай будет что-то вроде:

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

int main() 
{ 
    BST t; 

    t.insert("A"); 

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

О, теперь я понимаю, что вы подразумеваете, реализуя конструктор копирования. Теперь я вижу, что это действительно необходимо для того, чтобы код работал по назначению без прохождения b. Мой профессор никогда не говорил о правиле трех, поэтому я понятия не имел, но отныне я буду следить за ним. Спасибо огромное! – mooles

+0

Не проблема. Также следите за правилом пяти (в основном правило из трех с дополнительными методами обработки 'std :: move'). Более хорошее чтение здесь: http://en.cppreference.com/w/cpp/language/rule_of_three – user4581301

Смежные вопросы