2013-11-26 3 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.1GB이고 약 44,000,000 줄로 구성되어 있으므로 효율성을 향상시키는 방법에 대한 정보도 매우 유용 할 것입니다.

+0

* 표시되는 코드에서 * 세그먼트 화 오류로 중지됩니까? 선택한 디버거 (gdb, visual studio)로 프로그램을 실행하고 실패한 행 번호를 다시보고하십시오. 또한, 1829/1830에 관한 특별한 내용이 있습니까? 어쩌면 파싱 코드에 따라 선 형식 중 하나가 처음 나타나는 것입니까? – codeling

+0

상자에 얼마나 많은 RAM이 있습니까? 아마 메모리가 부족하고 할당 중 하나가 실패하고 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에 포인터를 사용하지 마십시오.
  • 일반적으로 포인터가 필요하지 않으면 포인터를 사용하지 마십시오.

그리고 여기에 버그가이 :

당신이 laready 루프의 몸 밖에서 성적 증명서 선언 한 이후
delete transcript; 

    RefSeqTranscript *transcript = new RefSeqTranscript(); 

, 여기에 같은 이름을 가진 새로운 변수를 숨 깁니다. 이로 인해 메모리 누수가 발생하고 더 나아가 바깥 쪽 스크립트를 지우고 아무것도 바꾸지 않습니다. 따라서 다음 반복에서 충돌이 발생할 수 있습니다.

+0

감사합니다, 당신이 지적한 버그가 문제를 해결했습니다. 포인터를 사용하지 않은 이유는 무엇입니까? –

+0

@DavidBrown 포인터를 사용할 때마다 잠재적 인 메모리 누수가 있습니다. 수명이 컴파일러에 의해 관리되는 객체를 사용하면 메모리 누수를 만들지도조차 없습니다. – Johan

+0

원시 포인터를 사용할 위험성 외에도 힙 메모리 할당과 관련된 특정 오버 헤드가 있습니다. – Eugene