添加约10000个密钥后,无序映射中的分割错误
segmentation fault in unordered_map after ~ 10000 keys added
当datact=10736尝试插入到一个无序映射中时,会发生分段故障(请参阅注释行,调用会为其抛出故障)。请参阅下面的尝试修复程序。
当抛出SIGSEGV时,它将我指向hashtable_policy.h
的第764行
INPUT:列1=计数,列2=16个字符串的数据文件
目的:通过将1个取代的不同序列的所有计数相加,对16个字符序列进行聚类。看到的第一个序列是"原点",通过它可以识别它的所有1-替换友元。
PSEUDOCODE:对于文件中的每一行:
-
读取计数,读取顺序。
-
如果序列key_value存在于哈希"location"(类型unordered_map),添加当前计数;
-
否则,创建一个新的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();
}
探索。
- 添加了什么密钥并不重要,当
datact==10736
和j=13
添加到(unordered_map)位置的键会导致SIGSEGV - 有问题的代码行(由上面的注释标记)在之前被调用过多次,并且操作正确
- 将无序映射交换为映射会导致相同的事件,但数据计数不同(更高)。仍低(
datact
之间==16-35千) - 重写这段代码几乎完全正确,但据我所知,使用随机生成的16个字符序列可以完美地工作(没有数据量高达200000的segfault,没有测试更高)
- 在(4)中的代码中,确实出现了10000左右的rehash,这可能是相关的,也可能是巧合
如果需要,我可以发布读取的数据文件。
编辑:已解决将unordered_map <string,unsigned int*> location
替换为unordered_map <string,unsigned int> location
(value_type为int而非int*)。现在value_type将索引保存在ctarr[]中。运行良好。谢谢
vector::resize()
时,指向vector
元素的指针可能无效。这是因为为了找到适合新大小的连续内存块,可能必须四处移动整个数据。换句话说:一旦调用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()
开始,只有当我能够毫无疑问地证明边界检查是实现这一特定目的的性能瓶颈时,我才会切换)。这对你的问题没有帮助,但通常对发现错误有着宝贵的帮助。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 将函数类成员映射到类本身内部
- 如何在C++中从字符串中分割字符
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 使用std::函数映射对象方法
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- C++映射分割错误(核心转储)
- 内联映射初始化的动态atexit析构函数崩溃
- 使用"std::unordereded_map"映射到"std::list"对象
- 如何从多映射中删除特定的重复项
- 在未初始化映射的情况下,将值插入到映射的映射中
- QT通过C++添加映射QML项目
- 在c++中访问int到类对象的映射时出错
- 删除映射和分割错误中的一个过去结束元素
- 在公共方法中插入映射(私有属性)后出现分割故障
- 在类的联合内部访问映射会产生分割错误
- 添加约10000个密钥后,无序映射中的分割错误
- 映射与类值分割故障