Вложенная итерация stdext :: hash_map

У меня проблема с UNORDERED_MAP

Я использую эти два typedefs:

typedef UNORDERED_MAP<uint32, WorldSession*> SessionCharMap;
typedef UNORDERED_MAP<uint32, SessionCharMap > SessionMap;

которые используют следующее определение:

#  define UNORDERED_MAP stdext::hash_map

Так что в основном это 1 контейнер, содержащий много контейнеров другого типа SessionMap — *> SessionCharMap.

в следующем m_sessions используется:

SessionMap m_sessions;

Он используется для назначения Sessionid нескольких субидов, чтобы обрабатывать их по-разному.
Если uint32 из SessionCharMap == NULL, Учетная запись еще не полностью вошла и должна выбрать Персонажа. Это работает нормально, пока я не хочу переназначить зарегистрированный сеанс на не полностью зарегистрированный сеанс:

bool DeassignCharFromSession(uint32 acc, uint32 chr){

SessionMap::iterator itr2;
for (itr2 = m_sessions.begin(); itr2 != m_sessions.end(); itr2++){
if(itr2->first == acc){
for (SessionCharMap::iterator itr = itr2->second.begin(); itr != itr2->second.end(); itr++){
if( itr->first == chr &&
itr->second){
WorldSession* ses = itr->second;
itr2->second.erase(itr);
m_sessions[acc][NULL] = ses;
sLog.outDebug("############################################1 %d %d",itr2->first,itr->first);

return true;
}
}
}
}

return false;
}

Этот шов кода нарушает мою переменную m_sessions, потому что цикл итерации, выполняемый над ней для обновления сеансов, больше не прерывается.
Я хочу упомянуть, что я уже пробовал «itr2-> second [NULL] = ses;»

void UpdateSessions( uint32 diff )
int i = 0;
for (SessionMap::iterator itr2 = m_sessions.begin(); itr2 != m_sessions.end(); ++itr2){
int j = 0;
for(SessionCharMap::iterator itr = itr2->second.begin(); itr != itr2->second.end(); ++itr){
//WorldSession * pSession = itr->second;
debug_log("########################### 123 %d %d %d %d %d",itr2->first,itr->first, itr->second ? 1 : 0, i,j);
j++;
WorldSessionFilter updater(itr->second);

if(!itr->second){
debug_log("########################### 1231 %d %d",itr2->first,itr->first);
//itr2->second.erase(itr);
} else
if(!itr->second->Update(updater))
{
debug_log("########################### 1233");
RemoveQueuedSession(itr->second);
debug_log("########################### 1234");
itr2->second.erase(itr);
debug_log("########################### 1235");
delete itr->second;
debug_log("########################### 1236");
}
}
i++;
}
}

После Debugoutput я получаю:

 2012-09-08 08:33:13 ############################################1 1 1
012-09-08 08:33:13 ########################### 123 1 0 0 0 1
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 2
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 3
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 4
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 5
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 6
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 7
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 8
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 9
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 10
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 11
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 12
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 13
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 14
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 15
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 16
2012-09-08 08:33:13 ########################### 1231 1 0
2012-09-08 08:33:13 ########################### 123 1 0 0 0 17

Счетчик i и j предназначен только для выхода отладки. Вы можете видеть, что счетчик j поднимается во внутренний Контейнер. Но у меня есть только 1 сессия онлайн. Если я хочу выйти из системы, это приводит к увеличению скорости чтения ~ 400 до 400;

Я не понимаю, почему цикл

for (SessionCharMap::iterator itr = itr2->second.begin(); itr != itr2->second.end(); itr++){...}

пробегает его границы. Пожалуйста, скажите мне, если вы нашли ошибку, я вне идей.

И еще одна вещь: процедура UpdateSession работает нормально при правильном входе в систему (только одна итерация на цикл for). Ошибка в первую очередь возникает при выходе из системы. Тогда итератор сходит с ума. Я предполагаю, что я неправильно обработал контейнер в DeassignCharFromSession.

ОБНОВЛЕНИЕ с помощью вас, ребята:

Исправленная сессия обновлений

void UpdateSessions( uint32 diff ){
int i = 0;
for (SessionMap::iterator itr2 = m_sessions.begin(); itr2 != m_sessions.end(); ++itr2){
int j = 0;
for(SessionCharMap::iterator itr = itr2->second.begin(); itr != itr2->second.end();){
//WorldSession * pSession = itr->second;
debug_log("########################### 123 %d %d %d %d %d",itr2->first,itr->first, itr->second ? 1 : 0, i,j);
j++;
WorldSessionFilter updater(itr->second);

debug_log("########################### 123 %d %d %d",itr2->first,itr->first, itr->second ? 1 : 0);
if(!itr->second){
//this case should never occur!
debug_log("########################### 1231 %d %d",itr2->first,itr->first);
++itr;
//itr2->second.erase(itr);
}else

if(!itr->second->Update(updater))
{
debug_log("########################### 1233");
RemoveQueuedSession(itr->second);
debug_log("########################### 1234");
delete itr->second;
debug_log("########################### 1235");
itr2->second.erase(itr++);
debug_log("########################### 1236");
} else {
++itr;
}
}
i++;
}
}

Исправлено DeassignCharFromSession:

bool DeassignCharFromSession(uint32 acc, uint32 chr){
if(m_sessions[acc][chr]){
sLog.outDebug("############################################1 %d %d",acc,chr);
m_sessions[acc][NULL] = m_sessions[acc][chr];
m_sessions[acc].erase(chr);
sLog.outDebug("############################################2");
return true;
}

debug_log("################################### UUU2");
return false;
}

Но проблема остается: цикл в UpdateSessions продолжает перебирать unordered_map. Это происходит 348 раз, а затем заканчивается нарушением прав доступа.
И я до сих пор смущен, почему

если (! itr-> второй) {..}

триггеры. поскольку в unordered_map должен быть только один допустимый сеанс.

0

Решение

Когда вы используете стирание, вы аннулирование итератора. Поэтому, когда вы пишете

itr2->second.erase(itr);

в UpdateSessions ты больше не можешь использовать itr так как он больше не указывает на члена вашей хэш-карты. Так что обе строки delete itr->second; и, что особенно важно, итерация цикла ++itr ошибки. Первая проблема легко решается, просто переключите порядок удаления и стирания

delete itr->second;
itr2->second.erase(itr);

Вторая проблема немного сложнее, в основном вы должны переписать ваш цикл следующим образом

for (SessionCharMap::iterator itr = itr2->second.begin(); itr != itr2->second.end(); )
{
...
if (itr->second->Update(updater))
{
++itr;
}
else
{
...
delete itr->second;
itr2->second.erase(itr++);
}
}

Таким образом, вы увеличиваете итератор до Вы вызываете erase, но поскольку вы используете оператор постинкрементного удаления, erase по-прежнему получает предыдущее значение итератора.

0

Другие решения

Решил проблему.
Итератор в UpdateSessions (см. Ниже) становится недействительным из-за удаления в DeassignCharFromSession.
решил это с перерывом. это приведет к тому, что некоторые сеансы будут ждать 2 цикла обновления.

///- Then send an update signal to remaining ones
debug_log("############################## OOOOO LOL");
int i = 0;
for (SessionMap::iterator itr2 = m_sessions.begin(); itr2 != m_sessions.end(); ++itr2){
int j = 0;
SessionCharMap::iterator itr;
for(itr = itr2->second.begin(); itr != itr2->second.end();){
//WorldSession * pSession = itr->second;
debug_log("########################### 123 %d %d %d %d %d",itr2->first,itr->first, itr->second ? 1 : 0, i,j);
j++;
WorldSessionFilter updater(itr->second);

debug_log("########################### 123 %d %d %d",itr2->first,itr->first, itr->second ? 1 : 0);
if(!itr->second){
//this case should never occur! but it does cuz iterator becomes invalid cuz of delete
debug_log("########################### 1231 %d %d",itr2->first,itr->first);
++itr;
break;
//itr2->second.erase(itr);
}else

if(!itr->second->Update(updater))
{
debug_log("########################### 1233");
RemoveQueuedSession(itr->second);
debug_log("########################### 1234");
delete itr->second;
debug_log("########################### 1235");
itr2->second.erase(itr++);
debug_log("########################### 1236");
} else {
++itr;
}
}
i++;
}
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector