将文本文件解析到列表中会出现分段错误

Parsing text file into list gives segmentation fault

本文关键字:分段 错误 列表 文件 文本      更新时间:2023-10-16

我在解析一个大文本文件时遇到了分段错误。该文件包含91529个信使核糖核酸转录本和这些转录本的详细信息。我已经创建了一个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行组成,因此任何关于如何提高效率的提示都将不胜感激。

这可能不是唯一的答案,但您有一个泄漏。。。

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

除非您提供更多详细信息,否则很难说有什么具体的:

  • 它撞在哪条线上了
  • 你真的同时需要所有这些成绩单吗

但我建议你改进一下:

  • 不要对RefSeqTranscript *transcript使用指针(或者至少使用智能指针)
  • 不要将指针用于Gene *gene
  • 一般来说,除非你真的需要,否则不要使用指针

这里有一个错误:

   delete transcript;
   RefSeqTranscript *transcript = new RefSeqTranscript(); 

由于您已经在循环的主体之外声明了transcript,所以在这里您可以用同名的新变量来隐藏它。这会导致内存泄漏,而且,您会删除外部转录本,并且不会用任何内容替换它。因此,您可能会在下一次迭代中崩溃。