嵌套的stdext :: hash_map迭代

时间:2012-09-08 07:10:54

标签: c++ unordered-map

我遇到有关UNORDERED_MAP

的问题

我正在使用这两个typedef:

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

使用以下定义:

#  define UNORDERED_MAP stdext::hash_map

基本上这就是包含许多其他类型SessionMap容器​​的容器 - *&gt; SessionCharMap。

使用以下m_sessions中的

SessionMap m_sessions;      

它用于为Sessionid分配几个子对象以不同方式处理它们。 如果SessionCharMap的uint32 == 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变量,因为运行它以更新Sessions的iterration循环不会再终止。 我想提一下,我已经尝试过“itr2-&gt; 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。您可以看到内部Container的j计数器。但我只有1个在线会议。如果我要注销它会导致j上升到~400读取随机存储器; - )。

我不明白为什么for循环

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

跑过它的边界。请告诉我你是否发现了我的错误。

另一件事:正确登录时UpdateSession例程工作正常(每个for循环只有一次迭代)。注销时首先出现错误。然后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结束。 我仍然困惑为什么

如果(itr-&GT;!第二){..}

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

2 个答案:

答案 0 :(得分: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仍然得到迭代器的前一个值。

答案 1 :(得分: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++;
}