У меня проблема с 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 должен быть только один допустимый сеанс.
Когда вы используете стирание, вы аннулирование итератора. Поэтому, когда вы пишете
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 по-прежнему получает предыдущее значение итератора.
Решил проблему.
Итератор в 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++;
}