0

我有一个关于 UNORDERED_MAP 的问题

我使用这两种类型定义:

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 几个 subid 以不同地处理它们。如果 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 的迭代循环不再终止。我想提一下,我已经尝试过“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 个在线会话。如果我想注销它会导致 j 上升到 ~400 读取随机内存;-)。

我不明白为什么for循环

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

跑过它的边界。如果您发现我没有想法的错误,请告诉我。

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

if(!itr->second){..}

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

4

2 回答 2

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++);
    }
}

这样,您在调用擦除之前递增迭代器,但因为您使用后递增运算符擦除仍然获得迭代器的先前值。

于 2012-09-08T07:33:46.450 回答
0

解决了问题。由于 DeassignCharFromSession 中的删除,UpdateSessions 中的迭代器(见下文)变得无效。休息一下就解决了。这将导致某些会话等待 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++;
} 
于 2012-09-11T23:32:41.167 回答