【问题标题】:EXC_BAD_ACCESS, calling getterEXC_BAD_ACCESS,调用getter
【发布时间】:2017-10-30 23:27:33
【问题描述】:

我不太擅长内存管理,希望有人能帮我解释一下为什么我会收到 EXC_BAD_ACCESS (code=1...) 错误。 Xcode说调用getWord()方法时出错。

我正在实现一个 trie 数据结构,当我尝试从我的节点获取单词时发生错误。我认为问题出在我的 add 或 addPhrase 方法上,但我不知道发生了什么。任何建议表示赞赏。

Trie 和节点类:

#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 - 只尝试从第一个节点开始的单词。

#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;
}

【问题讨论】:

  • 不确定(需要minimal reproducible example),但您很容易违反三规则。 What is The Rule of Three?
  • 这一行看起来很可疑:Node root = *new Node(); // 为什么不直接实例化为:Node root;代替?
  • @kvr 尝试了两种方式,但都没有任何区别。我只是忘了改回来。
  • 关于#include "Trie.cpp":建议不要包含cpp文件。包含头文件并编译源文件。
  • 当我输入“a b c d e”时,程序因stoi 的无效参数而崩溃。什么是触发您收到的错误的好输入集?

标签: c++ c++11 memory exc-bad-access trie


【解决方案1】:

您是否偶然地对 Java 有过一些经验?在任何情况下,关于 C++ 有几件重要的事情需要注意:简单的赋值或初始化不会将变量链接为对现有对象的引用,并且不需要关键字 new 来创建新对象。

Node current = this->root;

addaddPhrase 中的这一行创建了一个 Node 对象,它是您的 root 节点(子节点和所有节点)的副本。所以你对current 所做的任何事情都不会影响root。在main 的最后一行

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

无效,因为myTrie.root.children 仍然为空,可能导致您的崩溃(除非我错过了之前的问题)。

C++ 中的 new 关键字创建了一个具有动态存储持续时间的对象,而不是通常的自动存储持续时间,这意味着除非您在指向该对象的指针上使用 delete 关键字,否则该对象不会因任何原因而被销毁目的。所以任何时候你做类似的事情

Trie myTrie = *new Trie();

由于new,程序创建了一个没有名称的Trie 对象,然后通过从该对象复制创建myTrie 对象,但第一个对象将存在于程序的其余部分并被视为“泄露”。太多的泄漏,除了形式不好之外,还会增加程序对计算机内存的使用,这种方式在程序停止之前无法逆转。要默认构造一个Trie 对象,只需编写:

Trie myTrie;

addaddPhrase 中,您希望您的变量current 与不同的现有Node 对象相关,而不是在函数持续时间内存在的独立Node。这实际上是一个原始指针的用例:

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);
        }
    }
}

(注意current-&gt;children.back()current-&gt;children[current-&gt;children.size()-1] 的缩写。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 2015-02-17
    • 2011-02-25
    • 2017-03-23
    • 1970-01-01
    相关资源
    最近更新 更多