2010-05-18 32 views
1

我在调试分段错误时遇到了问题。我很感谢提示如何在问题上缩小范围。访问boost :: unordered_multimap或结构体时偶尔出现分段错误

时的迭代器尝试访问一个结构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; 

每个构件类别HostInfectionMap carriage。恢复时间和关联的主机标识符保存在优先级队列中。当在特定主机的特定菌株s的模拟中出现计划的恢复事件时,程序通过搜索该主机的carriage来查找其recT与恢复时间(double recoverTime)相匹配的Infection。 (对于那些不值得进入的原因,它不是作为权宜之计,我使用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 ...”。 recoverTime很好,并且代码中的assert(...)未被触发。

正如我所说的,在成千上万的成功恢复事件之后,这个seg故障“随机”出现。

你将如何去弄清楚发生了什么?我很想知道什么是错的,以及我如何进一步调查问题。


更新

我添加了一个新的断言,只是内部检查的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在Host.cpp主持人::恢复(此= 0x100530d80,S = 0,recoverTime = 635.91148029170529):317”

我不知道什么有用我可以在这里提取信息。


更新2

我的carriage.erase(it)后添加一个break;。这工作。

+0

你的调试环境是什么? Eclipse通常擅长在发生故障时暂停执行,以便检查调用堆栈。您是否尝试过每次通过循环打印与迭代器相关联的某个值来进行printf调试?你有没有检查ret.first和ret.last的值是否合理? – Bruce 2010-05-18 22:20:40

+0

我使用gdb,但显然不够好!将调查ret.first和ret.last。 – Sarah 2010-05-18 22:25:05

回答

7

纠正我,如果我错了,但我敢打赌,删除无序multimap中的项目将使所有指向它的迭代器失效。尝试“it = carriage.erase(it)”。你也必须做一些关于ret的事情。

更新回复您的最新更新:

原因终止循环的呼叫后,“carriage.erase(它)”修复了这一错误是因为你不再试图访问迭代器擦除。

+3

+1,只是'erase'不会返回下一个迭代器,您必须自己跟踪它。 – avakar 2010-05-18 22:23:28

+0

这并不会在for循环中增加它。 – 2010-05-18 22:24:30

+0

@Noah和@avakar:如果在特定的恢复时间内总是只有一次感染,您的建议是否会保留? (我已经证实,出现seg错误时就是这种情况。)使用“it = carriage.erase(it)”创建一个新的seg错误,该错误立即出现在模拟中。 – Sarah 2010-05-18 22:32:10

0

gcc -g编译程序并在gdb下运行它。当你遇到一个EXC_BAD_ACCESS崩溃时,你将进入gdb命令行。此时,您可以输入bt以获得回溯,这将告诉您如何达到发生崩溃的地步。

+0

我一直在盯着回溯一个小时。它指向我上面提到的路线。我将详细了解如何解读地址。 – Sarah 2010-05-18 22:22:09