std函数中的分段错误std :: _ Rb_tree_rebalance_for_erase()

时间:2010-05-19 20:34:33

标签: c++ segmentation-fault std

(注意任何未来的读者:错误,不出所料,是在我的代码而不是std :: _ Rb_tree_rebalance_for_erase())

我对编程有些新意,并且不确定如何处理似乎来自std函数的分段错误。我希望我做一些愚蠢的事情(即滥用容器),因为我不知道如何修复它。

准确的错误是

  

编程收到信号EXC_BAD_ACCESS,无法访问内存   原因:地址为KERN_INVALID_ADDRESS:0x000000000000000c
  std :: _ Rb_tree_rebalance_for_erase()中的0x00007fff8062b144   (gdb)回溯
   std :: _ Rb_tree_rebalance_for_erase()中的#0 0x00007fff8062b144()
   在stl_tree.h中的Simulation :: runEpidSim(this = 0x7fff5fbfcb20)中的#1 0x000000010000e593:1263
   main.cpp中的main()中的#2 0x0000000100016078:43

在分段错误更新两个容器的内容之前成功退出的函数。一个是boost::unordered_multimap,称为carriage;它包含一个或多个struct Infection个对象。另一个容器是std::multiset< Event, std::less< Event > > EventPQ类型,名为ce

void Host::recover( int s, double recoverTime, EventPQ & ce ) {

  // Clearing all serotypes in carriage
  // and their associated recovery events in ce
  // and then updating susceptibility to each serotype
  double oldRecTime;
  int z;
  for ( InfectionMap::iterator itr = carriage.begin(); itr != carriage.end(); itr++ ) {
    z = itr->first;
    oldRecTime = (itr->second).recT;
    EventPQ::iterator epqItr = ce.find( Event(oldRecTime) );
    assert( epqItr != ce.end() );
    ce.erase( epqItr );
    immune[ z ]++; 
  }
  carriage.clear();
  calcSusc(); // a function that edits an array 
  cout << "Done with sync_recovery event." << endl;
}

最后cout << 行出现在seg错误之前。

到目前为止,我的想法是在此功能之后立即在ce上尝试重新平衡,但我不确定为什么重新平衡会失败。


更新

当我删除ce.erase( epqItr );时,我已经确认seg故障消失了(虽然程序因其他原因立即崩溃)。我能够在代码中的另一个地方成功删除事件;我在那里用来擦除ce中的项目的代码与相同与此处的内容相同。

Backtracing 没有优化(谢谢,bdk)显示更多信息:

  

编程收到信号EXC_BAD_ACCESS,无法访问内存   原因:地址为KERN_INVALID_ADDRESS:0x000000000000000c
  std :: _ Rb_tree_rebalance_for_erase()中的0x00007fff8062b144   (gdb)回溯
   std :: _ Rb_tree_rebalance_for_erase()中的#0 0x00007fff8062b144()
   std :: _ Rb_tree中的#1 0x00000001000053d2,std :: less,&gt; std :: allocator&gt; :: erase(this = 0x7fff5fbfdfe8,__position = {_ M_node = 0x10107cb50})at&gt; stl_tree.h:1263
   在stl_multiset.h中std :: multiset,std :: allocator&gt; :: erase(this = 0x7fff5fbfdfe8,__position = {_ M_node = 0x10107cb50})中的#2 0x0000000100005417:346    在Simulation.cpp中的Simulation :: runEpidSim(this = 0x7fff5fbfcb40)中的#3 0x000000010000ba71:426
   Main.cpp中main()中的#4 0x000000010001fb31:43

除非Xcode读取行号错误,否则我的硬盘中唯一的stl_tree.h在第1263行是空白的。

有些人要求查看调用恢复的功能。这有点复杂:

struct updateRecovery{
updateRecovery( int s, double t, EventPQ & ce ) : s_(s), t_(t), ce_(ce) {}
  void operator() (boost::shared_ptr<Host> ptr ) {
   ptr->recover( s_, t_, ce_ );
  }
private:
  int s_;
  double t_;
  EventPQ & ce_;
};

// allHosts is a boost::multiindex container of boost::shared_ptr< Host > 
// currentEvents is the EventPQ container
// it is an iterator to a specific member of allHosts
allHosts.modify( it, updateRecovery( s, t, currentEvents ) );
cout << "done with recovery" << endl;

最后cout次打印。如果没有这个特定版本的恢复功能,代码就可以使用。

Noah Roberts正确地指出问题出在Simulation.cpp,第426行。跳到下面以寻找令人尴尬的解决方案。

3 个答案:

答案 0 :(得分:3)

在整个恢复通话中,你可能会抓住一个迭代器到ce。如果恢复发生删除该项,则迭代器将失效,并且将来的任何使用(例如尝试擦除它)都可能导致seg错误。

如果我们能够看到更多关于在恢复呼叫之前和之后如何使用ce的背景信息,将会有所帮助。

答案 1 :(得分:1)

问题是在Simulation.cpp的第426行,我试图删除EventPQ currentEvents(a.k.a。ce)容器中我刚刚删除recover()函数的事件。迭代器显然已失效。哑。

经验:

  • 调试尚未优化的代码
  • 密切关注非标准相关框架所暗示的内容

未来:在valgrind中跟踪记忆

我仍然难以理解调试器为什么在stl_tree.h中将我引入一个明显空白的行。

我非常感谢那些帮助我完成这项工作的人们。我将修改我的问题,以便对未来的读者更简洁。

答案 2 :(得分:0)

assert的调用可能不是使用您的配置编译的。生产代码中的断言通常是Bad Idea [TM]。

你也可能超过immune的界限。

尝试:

    if (epqItr != ce.end()) 
    {
        ce.erase(epqItr);
        if (z is within immune's bounds)
        {
            ++immune[z]; 
        }
    }