(Забележка за всички бъдещи читатели: Грешката, не е изненадващо, е в моя код, а не std::_Rb_tree_rebalance_for_erase () )
Донякъде съм нов в програмирането и не съм сигурен как да се справя с грешка в сегментирането, която изглежда идва от std функция. Надявам се, че правя нещо глупаво (т.е. злоупотребявам с контейнер), защото нямам представа как да го поправя.
Точната грешка е
Програма Получен сигнал exc_bad_access, не може да получи достъп до паметта.
Причина: kern_invalid_address на адрес: 0x000000000000000c
0x00007ff8062b144 в std :: _ rb_tree_rebalance_for_erase ()
(gdb) backtrace
#ttREF_TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRY )
#1 0x000000010000e593 в Simulation::runEpidSim (this=0x7fff5fbfcb20) в stl_tree.h:1263
#2 0x0000000100016078 в main () в main.cpp: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 <<
се появява непосредствено преди грешката на сегмента.
Идеята ми досега е, че повторното балансиране се опитва на ce
веднага след тази функция, но не съм сигурен защо повторното балансиране ще се провали.
Актуализация
Потвърдих, че грешката на seg изчезва (въпреки че след това програмата веднага се срива поради други причини), когато премахна ce.erase( epqItr );
. Мога да премахна събития успешно на друго място в кода; кодът, който използвам там, за да изтрия елементи в ce
, е идентичен с този тук.
Обратното проследяване без оптимизация (благодаря, bdk) разкрива много повече информация:
Програма Получен сигнал exc_bad_access, не може да получи достъп до паметта.
Причина: kern_invalid_address на адрес: 0x000000000000000c
0x00007ff8062b144 в std :: _ rb_tree_rebalance_for_erase ()
(gdb) backtrace
#ttREF_TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRE _TRY )
#1 0x00000001000053d2 в std::_Rb_tree, std::less, > std::allocator >::erase (this=0x7fff5fbfdfe8, __position={_M_node = 0x10107cb50}) в > stl_tree.h:1263
#2 0x0000000100005417 в std :: multiset, std :: alocator> :: erase (this = 0x7fff5fbfdfe8, __position = {_ m_node = 0x10107cb50}) при stl_multiset.h: 346 #3 0x0000010000ba71 в Simulation: Simulation.cpp:426
#4 0x000000010001fb31 в main () в main.cpp: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
разпечатки. Кодът работеше преди без тази конкретна версия на функцията за възстановяване.
Ноа Робъртс правилно отбеляза, че проблемът е в Simulation.cpp, ред 426. Отидете по-долу за неудобно решение.
ce
след като recover() завърши. - person Alex Korban   schedule 20.05.2010Simulation.cpp:426
или някъде по-високо в проследяването на стека. НоEXC_BAD_ACCESS
обикновено е дебел намек за дерефериране (или искане на стандартна функция да дереферира) невалиден итератор. - person wilhelmtell   schedule 20.05.2010