2013-02-06 26 views
1

嘗試插入到unordered_map時,當datact = 10736時發生分段錯誤(請參閱調用引發錯誤的註釋行)。請參閱下面的嘗試修復。添加了〜10000個密鑰後,unordered_map中的段錯誤

當SIGSEGV被拋出它指向我到線764 hashtable_policy.h

INPUT:用列1 =計數列2 = 16個字符的字符串

目的數據文件:通過將簇16個字符的序列的所有一起替換不同序列的1次計數。看到的第一個序列是識別其所有1位替換朋友的「原點」。

僞代碼:對於文件中的每一行:

  1. 閱讀數,閱讀順序。

  2. 如果序列key_value存在於散列'位置'(類型 unordered_map),則添加當前計數;

  3. 否則做一個新的key_value,讓它指向這裏的計數,並且 指定所有的1-替換序列也指向這個計數。

代碼:

#include <iostream> 
#include <fstream> 
#include <string> 
#include <sstream> 
#include <cmath> 
#include <vector> 
#include <unordered_map> 
#include <map> 

#include "matrix.h" 

using namespace std; 

int nuc2num(char currchar) 
{ // returns 0,1,2,3 for A,C,T,G respectively 
    int outnum; 

    if (currchar=='A') 
    { 
     outnum=0; 
    } 
    else if (currchar=='C') 
    { 
     outnum=1; 
    } 
    else if (currchar=='T') 
    { 
     outnum=2; 
    } 
    else 
    { 
     outnum=3; 
    } 
    return outnum; 
} 

int main(int argc, char* argv[]) 
{ 
    //command line arguments 
    // arg1=filename, arg2=barcode sequence length, arg3=#mismatches permitted 

    //input handling 
    // file format: column 1 | column 2 
    //    counts | sequence [int | string] 

    string filename; 
    string funnelstring; 

    // define lookup matrix; rows=ACTG, cols = ACTG without row element 
    Matrix <char> sub_lookup(4,3); 
    sub_lookup[0][0] = 'C'; 
    sub_lookup[0][1] = 'T'; 
    sub_lookup[0][2] = 'G'; 
    sub_lookup[1][0] = 'A'; 
    sub_lookup[1][1] = 'T'; 
    sub_lookup[1][2] = 'G'; 
    sub_lookup[2][0] = 'A'; 
    sub_lookup[2][1] = 'C'; 
    sub_lookup[2][2] = 'G'; 
    sub_lookup[3][0] = 'A'; 
    sub_lookup[3][1] = 'C'; 
    sub_lookup[3][2] = 'T'; 

    int L,k; 

    int j=0; 

    const int buffersize=10000; 
    int currentsize=buffersize; 

    int datact=0; 
    int currchar; 

    vector <unsigned int> ctarr(buffersize); 
    vector <string> seqarr(buffersize); 

    filename=argv[1]; 
    L=atoi(argv[2]); 
    k=atoi(argv[3]); 

    unsigned int sct; 
    int substrlen; 
    string sequence,textct; 
    ifstream seqfile (filename.c_str()); 

    //map <string,unsigned int*> location; 
    unordered_map <string,unsigned int*> location; 

    if (seqfile.is_open()) 
    { 
     getline(seqfile,textct,'\n'); 
     while (textct != "") 
     { 
      sct=atoi(textct.c_str()); 
      substrlen=textct.length(); 
      //cout << textct << endl; 
      sequence=textct.substr(substrlen-L,L); 
      //cout << sequence << endl; 

      //is there an associated guy? 
      if (location.find(sequence) != location.end()) //just asks whether this key has been assigned 
      { //there's a value in the region 
       *location[sequence]+=sct; 
      } 
      else 
      { //no value in region, make a footprint 
       ctarr[datact]=sct; 
       seqarr[datact]=sequence; 
       location[sequence]=&ctarr[datact]; //assign current key to point to data count 


       //assign k substitution "funnel" region to point to this count as well 
       for (j=0; j<L; j++) 
       { 
        funnelstring=sequence; 
        currchar = nuc2num(sequence[j]); 

        if (datact==10736 && j==13) 
        { 
         cout << "here" << endl; 
         cout << sequence << endl; 
        } 

        for (k=0; k<3; k++) 
        { 
         funnelstring[j]=sub_lookup[currchar][k]; 

//     if (datact==10736 && j==13) 
//     { 
//      cout << funnelstring << endl; 
//      cout << location.max_size() << " | " << location.size() << endl; 
//      string asdf; 
//      asdf="AAAAAAAAAAAAAAAA"; 
//      location[asdf]=&ctarr[datact]; //still segfaults 
//     } 

         if (location.find(funnelstring) == location.end()) // asks whether this key has been assigned 
         { //this region is not assigned to another funnel 
          location[funnelstring]=&ctarr[datact]; //LINE THAT CAUSES SIGSEGV 
         } 
        } 
       } 
       datact++; 
       cout << datact << endl; 
       if (datact>=currentsize) 
       { 
        ctarr.resize(currentsize+buffersize); 
        seqarr.resize(currentsize+buffersize); 
        currentsize+=buffersize; 
       } 
      } 

      getline(seqfile,textct,'\n'); 
     } 
     seqfile.close(); 
    } 

探索。

  1. 不要緊添加什麼鍵,當datact==10736j=13,任何 鍵添加到一個SIGSEGV(unordered_map)定位結果。
  2. 有問題的代碼行(標有上面的註釋)在之前被調用了很多次,並且運行正常。
  3. 在同一事件中交換unordered_map以獲取地圖結果,但在不同(更高)的datact計數處交換地圖結果。仍然很低(在datact == 16-35 千之間)。
  4. 幾乎準確地重寫了這段代碼,但隨機生成的16個字符的序列完美地工作,據我所知(沒有 數據段的段錯誤高達200,000,沒有測試更高)。
  5. 在(4)中的代碼中,似乎在10000左右有一個rehash,這可能是相關或巧合的。

如果需要,我可以發佈讀取的數據文件。

編輯:解決 代替unordered_map <string,unsigned int*> location,與unordered_map <string,unsigned int> location代替(VALUE_TYPE爲int代替INT *)。現在value_type持有ctarr []中的索引。運行良好。謝謝!

回答

5

當您撥打vector::resize()時,指向vector的元素可以失效。這是因爲可能需要移動整個數據才能找到適合新大小的連續內存塊。換句話說:只要您撥打resize,您的所有location數據突然變成無用的垃圾。

可能的解決方案:

  • location存儲所需的元素在ctarr作爲它的值,而不是指針的指數。 (這肯定不會改變你的程序的語義。)
  • location存儲實際的unsigned int值而不是指針。根據你的程序邏輯以及你如何改變和訪問這些數據,這可能不是你想要的。

還要注意的是,雖然在hashtable_policy.h發生段錯誤,這個錯誤已經無關的unordered_map(或vector)的實施 - 這完全是你爲vector::resize() ;-)不能讀取基準故障:http://www.cplusplus.com/reference/vector/vector/resize/(部分「迭代器的有效性」)


我注意到了有關你的代碼的另一件事是,你使用operator[]訪問您vector元素。這會禁止超出邊界檢查。如果我在代碼中遇到類似你的錯誤(難以追溯,因爲它發生在遠離我的錯誤代碼的地方),我的第一個過程是將operator[]替換爲vector::at()(實際上,我總是以at()開頭,並且只切換if我可以毫無疑問地證明邊界檢查是這個特定目的的性能瓶頸)。這不會對你的問題有所幫助,但往往是發現錯誤的寶貴幫助。

+0

有趣的是,我提出了指針的想法,因爲我認爲這會提高內存效率,最終導致頭痛。我沒有注意到這一點的一個原因是因爲它發生在10736年。如果它發生在10001年,我會立即查看矢量調整大小的情況。此外,它不應該嘗試添加到位置,除非該key_value是新的。我期望的錯誤是,程序運行良好,直到試圖迭代指針的目標,當指針不再指向實際值('* location [sequence] + = sct;')時 – vector07

+0

@ vector07 In一般來說,存儲指針可能很容易*少*存儲效率。在具有gcc的x86_64系統上,一個'unsigned int'(用於存儲值或索引)需要4個字節,而一個指針需要8個字節! – us2012