2016-04-09 9 views
2

initialisiert ich auf einer Programmieraufgabe für eine Klasse arbeite und bin ein wirklich seltsam Problem bekommen. Das technische Problem ist, dass ich einen Seg-Fehler bekomme, wenn ich versuche, etwas mit einem bestimmten Vektor zu tun, aber das Objekt, in dem es sich befindet, und das Objekt, in dem sich das Objekt befindet, verhält sich auch wirklich komisch. Ich vermute, dass es ein einfacher Syntaxfehler sein kann, von dem ich nicht weiß, wie er am besten zu lösen ist, also fangen wir damit an. Wenn diese Syntax ungültig oder nur halbgültig ist, müssen Sie wahrscheinlich den Rest nicht lesen (es sei denn, es ändert sich nicht).C++ Klassen nicht richtig

Wie auch immer, hier ist der Code, den ich besorgt bin (in der addRel Funktion meiner Database.h-Datei):

#ifndef DATABASE_H_ 
#define DATABASE_H_ 

#include "Parser.h" 
#include "Relation.h" 
#include <map> 

class Database { 
private: 
    std::map<std::string, Relation> relations; 
    std::stringstream out; 
public: 
    Database() {} 
    ~Database() {} 
    Relation* addRel(std::string RelName) { 
    Relation* tmp = getRel(RelName); 
    if(tmp == NULL) { 
     relations.insert(std::pair<std::string, Relation> (RelName, Relation(RelName))); //Is this a valid approach? 
     tmp = getRel(RelName); 
    } 
    return tmp; 
    } 
    bool findRel(std::string RelName) {return getRel(RelName) != NULL;} 
    Relation* getRel(std::string RelName) {return &relations.find(RelName)->second;} 
    ... 
}; 

Ich mag nicht genau ein Relation Objekt in dieser Funktion schaffen, aber ich brauche ein Relation Objekt haben, in relations.insert passieren, also rief ich nur den Konstruktor für Relation in den Funktionsparametern. Wenn es einen besseren Weg, dies zu tun, dass die Ursache für meine Trauer sein, was ich das Schlimmste befürchten, so ist hier eine Reihe von Code und Terminal-Ausgabe:

Tuple.h (kein CPP):

#ifndef TUPLE_H_ 
#define TUPLE_H_ 

#include <string> 
#include <vector> 

class Tuple : public std::vector<std::string> {}; 

//This approach was specifically encouraged by my instructor 

#endif 

Scheme.h (kein CPP):

#ifndef SCHEME_H_ 
#define SCHEME_H_ 

#include "Tuple.h" 
#include <utility> 

class Scheme { 
private: 
    std::vector<std::string> attrs; 
    std::string test; //for testing purposes 
public: 
    Scheme() { 
    attrs.clear(); 
    test = "This is a scheme."; 
    } 
    ~Scheme() {} 
    void addAttr(std::string newAttr) {attrs.push_back(newAttr);} 
    std::vector<std::string>* getAttrs() {return &attrs;} 
    void clear() {attrs.clear();} 
    std::string getTest() {return test;} 
}; 

#endif 

Relation.h (CPP nicht relevant):

#ifndef RELATION_H_ 
#define RELATION_H_ 

#include "Scheme.h" 
#include "Tuple.h" 
#include <set> 

class Relation { 
private: 
    std::string name; 
    Scheme idents; 
    ... 
public: 
    Relation(std::string newName) : name(newName) {} 
    ~Relation() {} 
    std::string getName() {return name;} 
    Scheme* getScheme() {return &idents;} 
    ... 
}; 

#endif 

Database.h (CPP-e Xcerpt unten):

#ifndef DATABASE_H_ 
#define DATABASE_H_ 

#include "Parser.h" 
#include "Relation.h" 
#include <map> 

class Database { 
private: 
    std::map<std::string, Relation> relations; 
    std::stringstream out; 
public: 
    Database() {} 
    ~Database() {} 
    Relation* addRel(std::string RelName) { 
    Relation* tmp = getRel(RelName); 
    if(tmp == NULL) { 
     relations.insert(std::pair<std::string, Relation> (RelName, Relation(RelName))); //Is this a valid approach? 
     tmp = getRel(RelName); 
    } 
    return tmp; 
    } 
    bool findRel(std::string RelName) {return getRel(RelName) != NULL;} 
    Relation* getRel(std::string RelName) {return &relations.find(RelName)->second;} 
    ... 
}; 

#endif 

Database.cpp (die interessanteste Datei):

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

using namespace std; 

void Database::evalSchemes(vector<Predicate> schemes) { 
    out << "Scheme Evaluation\n\n"; 
    for(unsigned int i = 0; i < schemes.size(); i++) { 
    string name = schemes[i].getName(); 
    Relation* trel = addRel(name); 
    Scheme* tsch = trel->getScheme(); 
    cout << "\nEvaluating scheme " << name << "\ni = " << i 
     << "\ntrel is " << trel->getName() << "\ntsch = " << tsch 
     << "\nTest = " << tsch->getTest() << "\n"; 
    tsch->clear();  //Segfaults here if this line is present 
    std::vector<Parameter> tvec = schemes[i].getVector(); 
    for(unsigned int j = 0; j < tvec.size(); j++) { 
     vector<string>* tattrs = tsch->getAttrs(); 
     string new_attr = tvec[j].getValue(); 
     cout << "\n\tAdding attribute " << new_attr << "\n\tj = " << j 
     << "\n\tVector size = " << tattrs->size() << "\n"; 
     tsch->addAttr(new_attr); //Segfaults here otherwise 
    } 
    } 
} 

... 

Main.cpp:

#include "Scanner.h" 
#include "Parser.h" 
#include "Database.h" 
#include <iostream> 

using namespace std; 

int main(int argc, char* argv[]) { 
    if(argc < 3) { 
    cout << "\nIncorrect program usage.\nPlease provide input and output file names.\n"; 
    return 0; 
    } 
    else { 
    Scanner mainScanner(argv[1]); 
    Parser mainParser; 
    Database mainDatabase; 
    mainScanner.scanAll(); 
    mainParser.importVector(mainScanner.getVector()); 
    mainParser.parseAll(); 
    DatalogProgram mainProg = mainParser.getProgram(); 

    //Everything up to this point works just fine 

    mainDatabase.evalSchemes(mainProg.getSchemes()); //Segfaults during this function 
    mainDatabase.evalFacts(mainProg.getFacts()); 
    mainDatabase.evalQueries(mainProg.getQueries()); 
    mainDatabase.output(argv[2]); 
    return 0; 
    } 
} 

Und hier ist der Ausgang aus dem Programm. Ich laufe innerhalb von Gdb in Ubuntu 14.04 und ZSH und benutze g ++ zum kompilieren, inklusive der Ausgabe eines Backtracks. Der zweite hat mehr Informationen, also habe ich die Cout-Ergebnisse dieses Programms kommentiert.

Wenn ich versuche, den Vektor zu löschen, bevor es zu ändern:

(gdb) run in30.txt act30.txt 
Starting program: /home/stephen/Dropbox/Code/CS_236/Lab3-Database/v1.0.1 in30.txt act30.txt 

Evaluating scheme SK 
i = 0 
trel is @���� ����X����������� ����������������������������������� 
tsch = 0x7fffffffd878 
Test = S 

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7b90350 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()() 
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
(gdb) bt 
#0 0x00007ffff7b90350 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()() 
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#1 0x000000000040ac7a in std::_Destroy<std::string> (__pointer=0x0) at /usr/include/c++/4.8/bits/stl_construct.h:93 
#2 0x0000000000409838 in std::_Destroy_aux<false>::__destroy<std::string*> (__first=0x0, 
    __last=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/bits/stl_construct.h:103 
#3 0x00000000004070aa in std::_Destroy<std::string*> (__first=0x0, 
    __last=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/bits/stl_construct.h:126 
#4 0x00000000004056c3 in std::_Destroy<std::string*, std::string> (__first=0x0, 
    __last=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/bits/stl_construct.h:151 
#5 0x0000000000405ab8 in std::vector<std::string, std::allocator<std::string> >::_M_erase_at_end (this=0x7fffffffd878, __pos=0x0) 
    at /usr/include/c++/4.8/bits/stl_vector.h:1352 
#6 0x0000000000404688 in std::vector<std::string, std::allocator<std::string> >::clear (this=0x7fffffffd878) 
    at /usr/include/c++/4.8/bits/stl_vector.h:1126 
#7 0x00000000004038c8 in Scheme::clear (this=0x7fffffffd878) at Scheme.h:19 
#8 0x0000000000401f81 in Database::evalSchemes (this=0x7fffffffd840, schemes=std::vector of length 1, capacity 1 = {...}) 
    at Database.cpp:15 
#9 0x000000000040c57f in main (argc=3, argv=0x7fffffffe238) at Main.cpp:26 
(gdb) 

Und hier ist was passiert, wenn ich diese Zeile auf Kommentar:

(gdb) run in30.txt act30.txt 
Starting program: /home/stephen/Dropbox/Code/CS_236/Lab3-Database/v1.0.1 in30.txt act30.txt 

Evaluating scheme SK //this is normal 
i = 0     //this is normal 
trel is @���� ����X����������� ����������������������������������� //should be the relation's name 
tsch = 0x7fffffffd878 //memory address, just to make sure it isn't NULL 
Test = S    //should be "This is a scheme." 

    Adding attribute A //this is normal 
    j = 0    //this is normal 
    Vector size = 17592168972444 /should be 0; I haven't done anything with this vector yet 

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7b9146f in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)() 
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
(gdb) bt 
#0 0x00007ffff7b9146f in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)() 
    from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#1 0x00000000004098ca in __gnu_cxx::new_allocator<std::string>::construct<std::string<std::string const&> > (this=0x7fffffffd878, 
    __p=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/ext/new_allocator.h:120 
#2 0x00000000004070ca in std::allocator_traits<std::allocator<std::string> >::_S_construct<std::string<std::string const&> >(std::allocator<std::string>&, std::allocator_traits<std::allocator<std::string> >::__construct_helper*, (std::string<std::string const&>&&)...) (__a=..., __p=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/bits/alloc_traits.h:254 
#3 0x000000000040572e in std::allocator_traits<std::allocator<std::string> >::construct<std::string<std::string const&> >(std::allocator<std::string>&, std::string<std::string const&>*, (std::string<std::string const&>&&)...) (__a=..., 
    __p=0x7ffff7dc04e0 <vtable for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >+64>) 
    at /usr/include/c++/4.8/bits/alloc_traits.h:393 
#4 0x0000000000404528 in std::vector<std::string, std::allocator<std::string> >::push_back (this=0x7fffffffd878, __x="A") 
    at /usr/include/c++/4.8/bits/stl_vector.h:905 
#5 0x0000000000403893 in Scheme::addAttr (this=0x7fffffffd878, newAttr="A") at Scheme.h:17 
#6 0x000000000040207a in Database::evalSchemes (this=0x7fffffffd840, schemes=std::vector of length 1, capacity 1 = {...}) 
    at Database.cpp:22 
#7 0x000000000040c559 in main (argc=3, argv=0x7fffffffe238) at Main.cpp:26 
(gdb) 

Da die trel Linie sieht nicht ganz wie es ist im Terminal, hier ist eine Bildschirmaufnahme dieses Bereichs der Ausgabe:

Terminal output

Ich würde wirklich absolut jede Einsicht, die Sie anbieten können, schätzen, da ich einen kompletten Verlust habe, teilweise weil ich einfach nicht weiß, wie ich die erste Mini-Frage in eine effektive Google-Suche umwandeln soll. Und wenn alles, was Sie antworten können, das erste Bit ist, wäre das immer noch absolut fantastisch.

+2

versuchen Sie, Ihr Programm zu vereinfachen und den Teil zu veröffentlichen, den Sie wirklich Hilfe brauchen mit – Pooya

Antwort

3

Ich entschuldige mich, wenn ich weg, aber ich glaube, ein Problem in Datenbank :: getRel sein kann:

return &relations.find(RelName)->second;

Die Suchfunktion kann das Rück Karte: end if RelName nicht gefunden wird, und map :: end sollte nicht dereferenziert werden. Sie sollten auf diese Möglichkeit testen und in diesem Fall NULL manuell zurückgeben.

+0

Ich habe keine Ahnung, wie das mein Problem verursacht hat, aber es hat es absolut behoben. Tausend Dank! –

+1

Kein Problem! Im Wesentlichen ist Folgendes passiert: Wenn Sie addRel zum ersten Mal ausführen, wird getRel ausgeführt, um zu prüfen, ob es bereits in der Map vorhanden ist. Unglücklicherweise gibt der map :: find-Aufruf map :: end zurück, und der Wert, der sich an dem durch -> second angegebenen Offset befindet, ist Müll. Wenn es zurückgegeben wird, erkennt Ihre Logik, dass es nicht NULL ist. Danach ist es nur ein Wartespiel, bis Sie versuchen, auf einen ungültigen Speicherort zuzugreifen. – Aenimated1