添加~10000个键后,在unordered_map中进行分段故障

时间:2013-02-06 08:15:02

标签: c++ segmentation-fault unordered-map sigsegv

当datact = 10736尝试插入到unordered_map时,会发生分段错误(请参阅调用行调用该错误的注释行)。请参阅下面的尝试修复。

当抛出SIGSEGV时,它指向hashtable_policy.h

的第764行

INPUT:数据文件,其中column1 = count,column2 = 16个字符的字符串

目的:通过将1-替换不同序列的所有计数加在一起来聚类16个字符的序列。看到的第一个序列是“起源”,通过它来识别所有1个替换的朋友。

PSEUDOCODE:对于文件中的每一行:

  1. 读取计数,读取序列。

  2. 如果序列key_value存在于散列'location'(类型 unordered_map),添加当前计数;

  3. 否则创建一个新的key_value,让它指向此处的计数,并且 指定所有1个替换序列也指向此计数。

  4. 代码:

    #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时,添加什么密钥并不重要 键添加到(unordered_map)位置会产生SIGSEGV。
    2. 有问题的代码行(由上面的注释标记)之前被多次调用,并且运行正常。
    3. 交换地图的unordered_map会导致同一事件,但数据类别不同(更高)。仍然很低(datact = = 16-35之间 万)。
    4. 几乎完全重写这段代码,但据我所知,随机生成的16个字符的序列完美无缺 数据集的段错误高达200,000,没有测试更高)。
    5. 在(4)的代码中,似乎在10000左右有一个rehash,这可能是相关的或巧合的。
    6. 如果需要,我可以发布读取的数据文件。

      编辑:已解决 而不是unordered_map <string,unsigned int*> location,而是替换为unordered_map <string,unsigned int> location(value_type是int而不是int *)。现在value_type保存ctarr []中的索引。运行很好。谢谢!

1 个答案:

答案 0 :(得分:5)

致电vector时,指向vector::resize()元素的指针无效。这是因为可能必须移动整个数据以便找到适合新大小的连续内存块。换句话说:只要您拨打resize,您的所有location数据就会突然变成无用的垃圾。

可能的解决方案:

  • locationctarr中所需元素的索引存储为其值而不是指针。 (这肯定不会改变你的程序的语义。)
  • 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()开头,只有在我能够无可置疑地证明边界检查是此特定目的的性能瓶颈时才会切换。这对您的问题没有帮助,但通常是发现错误的宝贵帮助。