2013-11-26 20 views
0

嘗試解析大文本文件時出現分段錯誤。該文件包含91 529 mRNA轉錄物和關於這些轉錄物的細節。我已經創建了一個RefSeqTranscript對象,它將採用這些細節。當我解析文件時,我創建了這些對象的列表並開始將這些細節放入這些列表中。它適用於1829年的第一批成績單,然後以分段錯誤崩潰。我跑的方法是:將文本文件解析到列表中會導致分段錯誤

void TranscriptGBFFParser::ParseFile(list<RefSeqTranscript> &transcripts, const char* filepath) 
{ 
    cout << "Parsing " << filepath << "..." << endl; 

    ifstream infile; 
    infile.open(filepath); 

    int num = 0; 
    RefSeqTranscript *transcript = new RefSeqTranscript(); 
    for(string line; getline(infile, line);) 
    { 
     in.clear(); 
     in.str(line); 

     if (boost::starts_with(line, "LOCUS")) 
     { 
      if((*transcript).transcriptRefSeqAcc.size() > 0) 
      {   
       cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl; 

       transcripts.push_back(*transcript); 
       delete transcript; 

       RefSeqTranscript *transcript = new RefSeqTranscript(); 

      } 
     } 
     else if (boost::starts_with(line, "  var")) 
     { 
      TranscriptVariation variant; 
      (*transcript).variations.push_back(variant);    
     } 
     //Store the definition of the transcript in the description attribute 
     else if (boost::starts_with(line, "DEFINITION")) 
     {   
      (*transcript).description = line.substr(12); 

      for(line; getline(infile, line);) 
      { 
       if(boost::starts_with(line, "ACCESSION ")) 
        break; 

       (*transcript).description += line.substr(12); 
      }  
     } 
     //The accession number and GI number are obtained from the VERSION line 
     else if (boost::starts_with(line, "VERSION")) 
     { 
      string versions = line.substr(12); 
      vector<string> strs; 
      boost::split(strs, versions, boost::is_any_of(" GI:"), boost::token_compress_on); 
      boost::trim_left(strs[0]); 

      (*transcript).transcriptRefSeqAcc = strs[0]; 
      (*transcript).gi = atoi(strs[1].c_str()); 
     } 
     //Gene information is obtained from the "gene" sections of each transcript 
     else if (boost::starts_with(line, "  gene")) 
     {   
      for(line; getline(infile, line);) 
      { 
       if(boost::starts_with(line.substr(21), "/gene=")) 
       { 
        Gene *gene = new Gene(); 

        string name = line.substr(27); 
        Utilities::trim(name, '\"'); 

        (*gene).geneName = name; 

        (*transcript).gene = *gene; 

        delete gene; 
        break; 
       } 
      } 
      (*transcript).gene.geneID = 0;  
     } 
     else if (boost::starts_with(line, "  CDS")) 
     { 
      (*transcript).proteinRefSeqAcc = "";    
     } 
     else if (boost::starts_with(line, "ORIGIN")) 
     { 
      (*transcript).sequence = "";    
     }  
    } 

    cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << endl; 

    transcripts.push_back(*transcript); 
    delete transcript;   

    cout << "No. transcripts: " << transcripts.size() << endl; 
    cout << flush; 

    infile.close(); 

    cout << "Finished parsing " << filepath << "." << endl; 
} 

我是新的C++,並且沒有對如何使用指針等等,所以我猜我可能做錯了那裏工作非常瞭解。我不明白爲什麼它在裁剪前幾乎可以使用2000個對象。

我解析該文件是2.1 GB和包括約44 000 000線等如何提高效率的技巧也將大加讚賞。

+0

*其中*代碼中顯示的代碼是否因分段錯誤而停止?使用您選擇的調試器(gdb,visual studio)運行該程序,並向其報告失敗的行號。此外,1829/1830線還有什麼特別之處?也許這是根據解析代碼看起來是第一次出現的行類型之一? – codeling

+0

你的盒子上有多少內存?您可能內存不足,其中一個分配失敗並返回NULL。 –

+0

爲什麼使用'transcript = new RefSeqTranscript'在最後複製它?像'RefSeqTranscript transcript'一樣只能使用堆棧中的對象。 – Johan

回答

0

這可能不是唯一的答案,但你有一個泄漏...

if (boost::starts_with(line, "LOCUS")) 
    { 
     if((*transcript).transcriptRefSeqAcc.size() > 0) 
     {   
      cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl; 

      transcripts.push_back(*transcript); 
      delete transcript; 
      // LEAK! 
      RefSeqTranscript *transcript = new RefSeqTranscript(); 

     } 
    } 

你大概的意思是:

transcript = new RefSeqTranscript();

+0

這個修好了,謝謝!!!!! :) –

0

很難說具體的事情,除非你提供一些更多細節:

  • 它墜毀在哪條線?
  • 你是否真的需要所有這些成績單在同一時間?

不過,我會建議你幾個改進:

  • 不要使用指針(或至少使用智能指針)爲RefSeqTranscript *transcript;
  • 請勿使用指針Gene *gene;
  • 一般來說,不要使用指針,除非你真的需要它們;

而你在這裏有一個BUG:

delete transcript; 

    RefSeqTranscript *transcript = new RefSeqTranscript(); 

既然你laready宣佈循環體外轉錄,在這裏你用相同名稱的新變量將其隱藏。這會導致內存泄漏,此外,您刪除了外部副本,並且不會將其替換爲任何內容。所以,你可能會在下一次迭代中崩潰。

+0

謝謝,你指出的錯誤解決了這個問題。不使用指針的原因是什麼? –

+0

@DavidBrown每次使用指針時,都有可能發生內存泄漏。當您使用生命週期由編譯器管理的對象時,您甚至沒有機會創建內存泄漏。 – Johan

+0

除了使用原始指針的危險之外,還有一些與堆內存分配相關的開銷。 – Eugene