2012-09-08 79 views
0

我有关于问题UNORDERED_MAP嵌套stdext ::的hash_map迭代

IM使用这两种类型定义:

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

其使用以下定义:

# define UNORDERED_MAP stdext::hash_map 

所以basicly这就是1个容器包含其他类型SessionMap - *> SessionCharMap的许多容器。在以下m_sessions

用于:

SessionMap m_sessions;  

其用于分配的SessionID几个subids以不同的方式处理它们。 如果SessionCharMap == NULL的uint32帐户尚未完全登录并且必须选择一个字符。这工作得很好,直到我想取消分配在会议的一项记录到一个Session中不完全记录:

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变量,因为iterration循环运行在它更新会话不会终止了。 我想提一下,我已经尝试过“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计数器只为debugoutput。你可以看到j计数器正在向内容器上升。但我只有1个会话在线。如果我想注销它,会导致j读到〜400读随机存储器;-)。

我不明白为什么for循环

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

运行在它的边界。请告诉我,如果你发现我错了我的想法。

另一件事:UpdateSession例程在正确登录时正常工作(每个for-loop只有一次迭代)。错误首先发生在注销时。然后iterrator疯了。我的猜测是,我错误地处理了DeassignCharFromSession中的容器。

更新你们的帮助:

更正UpdateSession

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次,然后以Accessviolation结束。 和IM仍然困惑,为什么

如果(!itr->第二){..}

触发器。因为在unordered_map中应该只有一个有效的会话。

+0

为什么使用2个循环代替函数中建立的hash_map:m_sessions [acc] [chr]首先。 –

+0

不错的会尝试,但只适用于删除部分,因为我需要循环所有登录的会话。 – Dornhoeschen

回答

0

当您使用擦除你是无效的迭代器。所以,当你在写UpdateSessions

itr2->second.erase(itr); 

你可以不再使用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++); 
    } 
} 

这样你递增迭代器你叫擦除之前,但因为你使用递增运算符擦除仍然得到迭代器的前值。

+0

谢谢,我认为解决了一些问题,仍然j增加了348次,它只应该是1x。更正的代码有问题;-) – Dornhoeschen

0

解决了这个问题。 由于DeassignCharFromSession中的删除,UpdateSessions中的iterrator(见下文)变得无效。 解决了它。这将导致一些会话等待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++; 
}