ошибка сегментации в unordered_map после добавления ~ 10000 ключей

Ошибка сегментации возникает, когда datact = 10736 при попытке вставить в unordered_map (см. Закомментированную строку, для которой вызов вызывает ошибку). Смотрите ниже для попыток исправить.

Когда SIGSEGV брошен, он указывает мне на строку 764 hashtable_policy.h

INPUT: файл данных с column1 = count, column2 = 16-символьные строки

НАЗНАЧЕНИЕ: кластеризация 16-символьных последовательностей путем сложения всех количеств 1-подстановок различных последовательностей. Первая видимая последовательность — это «источник», по которому идентифицируются все его друзья с 1 заменой.

PSEUDOCODE: для каждой строки в файле:

  1. прочитайте счет, прочитайте последовательность.

  2. если последовательность key_value существует в хеше ‘location’ (введите
    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==10736 а также j=13, любой
    ключ, добавленный к (unordered_map) местоположению, приводит к SIGSEGV.
  2. Строка кода, о которой идет речь (отмечена комментарием выше), вызывается много раз и работает правильно.
  3. Замена unordered_map для карты приводит к тому же событию, но с другим (большим) количеством данных. Все еще низко (между datact== 16-35
    тысяча).
  4. Переписать этот код почти точно, но с произвольно сгенерированными 16-символьными последовательностями, насколько я могу судить, работает отлично (нет
    segfaults для данных до 200 000, тест не выше).
  5. В коде (4) кажется, что около 10000 есть перефразировка, которая может быть связана или совпадать.

При необходимости я могу опубликовать файл данных, который читается.

РЕДАКТИРОВАТЬ: Решено
Вместо unordered_map <string,unsigned int*> location, заменен на unordered_map <string,unsigned int> location (value_type это int вместо int *). Теперь value_type содержит индекс в ctarr []. Работает нормально. Спасибо!

1

Решение

Указатели на vector элементы могут быть признаны недействительными при вызове vector::resize(), Это потому, что все данные, возможно, придется перемещать, чтобы найти непрерывный блок памяти, который соответствует новому размеру. Другими словами: как только вы позвоните resize, все твои location данные внезапно становятся бесполезным мусором.

Возможные решения:

  • Позволять location сохранить индекс необходимого элемента в ctarr как его значение, а не указатель. (Это, конечно, не изменит семантику вашей программы.)
  • Позволять location сохранить фактическое unsigned int значение вместо указателя. В зависимости от логики вашей программы и того, как вы изменяете эти данные и обращаетесь к ним, это может быть не то, что вам нужно.

Также обратите внимание, что хотя segfault происходит в hashtable_policy.hэта ошибка не имеет ничего общего с реализацией unordered_map (или же vector) — это полностью ваша вина, что вы не прочитали ссылку на vector::resize() ;-): http://www.cplusplus.com/reference/vector/vector/resize/ (раздел «Действительность итератора»)


Еще одна вещь, которую я заметил в вашем коде, это то, что вы используете operator[] для доступа к вашему vector элементы. Это отключает внеплановую проверку. Если я столкнусь с ошибкой, подобной вашей, в моем коде (трудно отследить, потому что это происходит где-то далеко от моего ошибочного кода), мой первый путь действий будет заменой operator[] за vector::at() (на самом деле, я всегда начинаю с at() и переключайтесь только в том случае, если я могу вне всяких разумных сомнений доказать, что проверка границ является узким местом производительности для этой конкретной цели). Это не помогло бы решить вашу проблему, но часто является неоценимой помощью в выявлении ошибок.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]