2017-10-30 5 views
0

Ich bin nicht sehr gut mit Speicherverwaltung und ich hoffe, dass jemand helfen kann, mir zu erklären, warum ich den Fehler EXC_BAD_ACCESS (code = 1 ...) bekomme. Xcode besagt, dass der Fehler beim Aufruf der Methode getWord() auftritt.EXC_BAD_ACCESS, calling getter

Ich implementiere eine Trie Datenstruktur und der Fehler tritt auf, wenn ich versuche, ein Wort von meinem Knoten zu bekommen. Ich denke, das Problem ist mit meiner add oder addPhrase-Methode, aber ich kann nicht herausfinden, was los ist. Irgendwelche Vorschläge werden geschätzt.

Trie und Knotenklasse:

#include <iostream> 
#include <cstdlib> 
#include <cstring> 
#include <string> 
#include <vector> 
#include <sstream> 


using namespace std; 


class Node 
{ 
private: 
    string word; 
    bool endOfSentence = false; 
    int weight = -1; 


public: 

    vector<Node> children = {}; 

    Node() { 
     this->setWord(""); 
    } 

    Node(string s){ 
     this->setWord(s); 
    } 

    string getWord(){ 
     return this->word; 
    } 
    /*vector<Node> getChildren() { //children private 
     return this->children; 
    }*/ 
    void setWord(string s) { 
     this->word = s; 
    } 

    void setEOS(){ 
     this->endOfSentence = true; 
    } 

    void setWeight(int weight){ 
     this->weight = weight; 
    } 
}; 


class Trie 
{ 
public: 
    Node root = *new Node(); 

    string get(string p) { 
     string s = "stub"; 
     return s; 
    } 

    void add(vector<string> phrase, int weight){ 
     Node current = this->root; 
     vector<string> sentence = phrase; 
     int w = weight; 
     int found = -1; 

     for (int i = 0; i < current.children.size(); i++) { 
      if (phrase[0] == current.children[i].getWord()) { 
       found = i; 
      } 
     } 
     if (found >= 0) { 
      current = current.children[found]; 
      sentence.erase(sentence.begin()); 
      add(sentence,w); 
     } 
     else { 
      addPhrase(sentence,w); 
     } 
    } 

    void addPhrase(vector<string> phrase, int weight) { 
     Node current = this->root; 
     for (int i = 0; i < phrase.size(); i++) { 
      Node temp = *new Node(phrase[i]); 
      current.children.push_back(temp); 
      current = current.children[current.children.size() - 1]; 
      if (i == phrase.size() - 1) { 
       current.setEOS(); 
       current.setWeight(weight); 
      } 
     } 
    } 
}; 

Main - versucht nur auf das Wort von dem ersten Knoten.

#include "Trie.cpp" 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <vector> 

using namespace std; 

int main(int argc, char* argv[]) { 
    // Initialize trie up here 
    Trie myTrie = *new Trie(); 

    // parse input lines until I find newline 
    for(string line; getline(cin, line) && line.compare("");) { 
     stringstream ss(line); 
     string string_weight; 
     ss >> string_weight; 
     int weight = stoi(string_weight); 

     // I am just going to put these words into a vector 
     // you probably want to put them in your trie 

     vector<string> phrase = {}; 
     for(string word; ss >> word;) { 
      phrase.push_back(word); 
     } 


     myTrie.add(phrase, weight); 


    } 
    // parse query line 
    string query; 
    getline(cin, query); 

    cout << myTrie.root.children[0].getWord() << endl; 



    return 0; 
} 
+0

Inconclusive (Need [MCVE]), aber sie sind anfällig für drei Verletzungen Regel. [Was ist die Dreiregel?] (Https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – user4581301

+1

Diese Zeile sieht verdächtig aus: Knoten root = * new Node(); // Warum nicht einfach instanziieren als: Knoten root; stattdessen? – kvr

+0

@kvr versuchte beide Wege, keiner macht einen Unterschied. Ich hatte gerade vergessen, es wieder zu ändern. – Dez

Antwort

0

Haben Sie etwas Erfahrung mit Java haben, zufällig? In jedem Fall gibt es ein paar wichtige Dinge, die in C++ zu beachten sind: Eine einfache Zuweisung oder Initialisierung verknüpft eine Variable nicht als Verweis auf ein vorhandenes Objekt, und das Schlüsselwort new wird nicht benötigt, um neue Objekte zu erstellen.

Node current = this->root; 

Diese Linie, die beide in add und addPhrase, schafft ein Node Objekt, das eine Kopie Ihres root Knoten (Kinder und alle). Alles, was Sie an current tun, hat keinen Einfluss auf root. Und ganz am Ende von main, die Leitung

cout << myTrie.root.children[0].getWord() << endl; 

ungültig ist, weil myTrie.root.children noch leer ist, möglicherweise den Absturz verursacht (es sei denn, ich ein früheres Problem verpasst). Das Schlüsselwort in C++ erstellt ein Objekt mit dynamischer Speicherdauer anstelle der üblichen automatischen Speicherdauer. Dies bedeutet, dass das Objekt aus keinem Grund zerstört wird, es sei denn, Sie verwenden das Schlüsselwort delete in einem Zeiger auf dieses Objekt. Also jedes Mal, wenn so etwas wie

Trie myTrie = *new Trie(); 

das Programm erstellt ein Trie Objekt ohne einen Namen wegen des new, dann das Objekt myTrie erzeugt durch von diesem Objekt zu kopieren, aber das erste Objekt wird für den Rest des existiert Programm und gilt als "durchgesickert". Zu viele undichte Lecks erhöhen die Programmnutzung des Computerspeichers auf eine Weise, die nicht rückgängig gemacht werden kann, bis das Programm beendet wird. Auf die Standard-Konstrukt ein Trie Objekt, dann ist es genug, nur schreiben:

Trie myTrie; 

In add und addPhrase, Sie möchten, dass Ihre Variable current auf unterschiedliche beziehen bestehenden Node Objekte, keine unabhängige Node sein, die für die Dauer lebt der Funktion. Dies ist eigentlich ein Anwendungsfall für einen Rohzeiger:

void addPhrase(vector<string> phrase, int weight) { 
    Node* current = &this->root; 
    for (int i = 0; i < phrase.size(); i++) { 
     Node temp(phrase[i]); 
     current->children.push_back(temp); 
     current = &current->children.back(); 
     if (i == phrase.size() - 1) { 
      current->setEOS(); 
      current->setWeight(weight); 
     } 
    } 
} 

(Hinweis current->children.back() ist ein kürzerer Weg current->children[current->children.size()-1] zu sagen.)