访问 boost::unordered_multimap 或 struct 时出现罕见的分段错误
我在调试分段错误时遇到问题。我希望得到有关如何缩小问题范围的提示。
当迭代器尝试访问结构体 Infection
的元素时,会出现该错误,定义为:
struct Infection {
public:
explicit Infection( double it, double rt ) : infT( it ), recT( rt ) {}
double infT; // infection start time
double recT; // scheduled recovery time
};
这些结构体保存在特殊结构 InfectionMap
中:
typedef boost::unordered_multimap< int, Infection > InfectionMap;
类 的每个成员>主机
有一个InfectionMap托架
。恢复时间和关联的主机标识符保存在优先级队列中。当在特定宿主中的特定菌株s
的模拟中出现计划的恢复事件时,程序会搜索该宿主的carriage
以查找感染
code> 的 recT
与恢复时间 (double receiveTime
) 匹配。 (由于不值得深究的原因,我使用 recT
作为 InfectionMap
的关键并不方便;菌株 s
更有用,并且可能存在相同菌株的双重感染。)
assert( carriage.size() > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
for ( it = ret.first; it != ret.second; it++ ) {
if ( ((*it).second).recT == recoverTime ) { // produces seg fault
carriage.erase( it );
}
}
我在上面指定的行上收到“程序收到信号 EXC_BAD_ACCESS,无法访问内存。原因:地址处的 KERN_INVALID_ADDRESS...”。恢复时间没问题,代码中的assert(...)
也没有跳闸。
正如我所说,这个段错误是在数千次成功恢复事件之后“随机”出现的。
您将如何弄清楚发生了什么事?我希望了解可能出现的问题以及如何进一步调查该问题。
更新
我在 for 循环内添加了一个新的断言和检查:
assert( carriage.size() > 0 );
assert( carriage.count( s ) > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
cout << "carriage.count(" << s << ")=" << carriage.count(s) << endl;
for ( it = ret.first; it != ret.second; it++ ) {
cout << "(*it).first=" << (*it).first << endl; // error here
if ( ((*it).second).recT == recoverTime ) {
carriage.erase( it );
}
}
EXC_BAD_ACCESS 错误现在出现在 (*it).first
调用中,在数千次成功之后再次出现恢复情况。谁能告诉我如何找出这个问题是如何产生的?我正在尝试使用gdb。回溯中的帧 0 读取
“#0 0x0000000100001d50 in Host::recover (this=0x100530d80, s=0,recoverTime=635.91148029170529) at Host.cpp:317”
我不确定我可以在这里提取什么有用的信息。
更新 2
我在 carriage.erase(it)
之后添加了 break;
。这有效。
I'm having trouble debugging a segmentation fault. I'd appreciate tips on how to go about narrowing in on the problem.
The error appears when an iterator tries to access an element of a struct Infection
, defined as:
struct Infection {
public:
explicit Infection( double it, double rt ) : infT( it ), recT( rt ) {}
double infT; // infection start time
double recT; // scheduled recovery time
};
These structs are kept in a special structure, InfectionMap
:
typedef boost::unordered_multimap< int, Infection > InfectionMap;
Every member of class Host
has an InfectionMap carriage
. Recovery times and associated host identifiers are kept in a priority queue. When a scheduled recovery event arises in the simulation for a particular strain s
in a particular host, the program searches through carriage
of that host to find the Infection
whose recT
matches the recovery time (double recoverTime
). (For reasons that aren't worth going into, it's not as expedient for me to use recT
as the key to InfectionMap
; the strain s
is more useful, and coinfections with the same strain are possible.)
assert( carriage.size() > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
for ( it = ret.first; it != ret.second; it++ ) {
if ( ((*it).second).recT == recoverTime ) { // produces seg fault
carriage.erase( it );
}
}
I get a "Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_INVALID_ADDRESS at address..." on the line specified above. The recoverTime is fine, and the assert(...)
in the code is not tripped.
As I said, this seg fault appears 'randomly' after thousands of successful recovery events.
How would you go about figuring out what's going on? I'd love ideas about what could be wrong and how I can further investigate the problem.
Update
I added a new assert and a check just inside the for loop:
assert( carriage.size() > 0 );
assert( carriage.count( s ) > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
cout << "carriage.count(" << s << ")=" << carriage.count(s) << endl;
for ( it = ret.first; it != ret.second; it++ ) {
cout << "(*it).first=" << (*it).first << endl; // error here
if ( ((*it).second).recT == recoverTime ) {
carriage.erase( it );
}
}
The EXC_BAD_ACCESS error now appears at the (*it).first
call, again after many thousands of successful recoveries. Can anyone give me tips on how to figure out how this problem arises? I'm trying to use gdb. Frame 0 from the backtrace reads
"#0 0x0000000100001d50 in Host::recover (this=0x100530d80, s=0, recoverTime=635.91148029170529) at Host.cpp:317"
I'm not sure what useful information I can extract here.
Update 2
I added a break;
after the carriage.erase(it)
. This works.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果我错了,请纠正我,但我敢打赌,删除无序多重映射中的项目会使指向它的所有迭代器无效。尝试“it=carriage.erase(it)”。你还必须对 ret 做一些事情。
更新回复您的最新更新:
调用“carriage.erase(it)”修复错误后打破循环的原因是因为您停止尝试访问已擦除的迭代器。
Correct me if I'm wrong but I would bet that erasing an item in an unordered multimap invalidates all iterators pointing into it. Try "it = carriage.erase(it)". You'll have to do something about ret as well.
Update in reply to your latest update:
The reason breaking out of the loop after calling "carriage.erase(it)" fixed the bug is because you stopped trying to access an erased iterator.
使用
gcc -g
编译程序并在gdb
下运行。当您遇到EXC_BAD_ACCESS
崩溃时,您将进入 gdb 命令行。此时,您可以输入bt
来获取回溯,这将显示您如何到达崩溃发生的位置。Compile the program with
gcc -g
and run it undergdb
. When you get anEXC_BAD_ACCESS
crash you'll drop into the gdb command line. At that point you can typebt
to get a backtrace, which will show you how you got to the point where the crash occurred.