2016-04-09 103 views
2

我正在爲一個類進行編程分配,並且正在得到一個非常奇怪的問題。技術問題是,當我嘗試對某個特定向量執行任何操作時,我遇到了seg錯誤,但是它所在的對象以及對象所在的對象的行爲真的很奇怪。我懷疑這可能是一個簡單的語法錯誤,我不知道如何最好地解決,所以讓我們從這個開始。如果這個語法無效或者只是半有效的,你可能不需要讀取其餘的(除非改變它不起作用)。C++類未正確初始化

總之,這裏的我很擔心(我Database.h文件addRel功能)代碼:

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

我完全不希望創建該功能的Relation對象,但我需要有一個Relation對象傳入relations.insert,所以我只是在函數參數中調用Relation的構造函數。如果有更好的方法來做到這一點,這可能是我的悲傷的原因,否則我擔心最壞的打算,所以這裏的一串代碼和終端輸出:

Tuple.h(沒有的.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(沒有的.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無關):

#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下面xcerpt):

#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(最有趣的文件):

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

下面是從程序的輸出。我在Ubuntu 14.04和ZSH的gdb中運行,使用g ++編譯,包括回溯的輸出。第二個有更多的信息,所以我評論了該計劃的結果。

如果我試圖修改它之前清除載體:

(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) 

而這裏的,如果我評論該行發生了什麼:

(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) 

由於trel線並不完全像它在終端中執行,這裏是該輸出區域的屏幕截圖:

Terminal output

我真的很感謝你能提供的任何洞察力,因爲我完全失去了,部分原因是我不知道如何將第一個小問題稱爲有效的Google搜索。如果你能回答的只是第一個,那仍然是絕妙的。

+2

嘗試簡化您的程序併發布您真正需要幫助的部分 – Pooya

回答

3

我道歉,如果我的路要走,但我相信一個問題可能出在數據庫:: getRel:

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

查找功能可能會返回地圖:如果最終RelName沒有找到,而map :: end不應該解除引用。你應該測試這種可能性,並在這種情況下手動返回NULL。

+0

我不知道這是如何導致我的問題,但它絕對修復它。太感謝了! –

+1

沒問題!基本上,這是發生了什麼:當你第一次運行addRel時,它運行getRel來檢查它是否已經存在於地圖中。不幸的是,map :: find調用返回map :: end,並且位於由 - > second指定的偏移量處的值是垃圾。所以當它返回時,你的邏輯發現它不是NULL。之後,它只是一個等待遊戲,直到您嘗試訪問無效的內存位置。 – Aenimated1