0

UNORDERED_MAP に関する問題があります

これら2つのtypedefを使用しています:

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

次の定義を使用しています:

#  define UNORDERED_MAP stdext::hash_map

したがって、基本的には、他のタイプの SessionMap -*> SessionCharMap の多くのコンテナーを含む 1 つのコンテナーです。

次の m_sessions で使用されます。

SessionMap m_sessions;      

Sessionid に複数のサブ ID を割り当てて、それらを異なる方法で処理するために使用されます。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 変数を壊します。私はすでに「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++){...}

その境界を越えます。間違いを見つけた場合は教えてください。私はアイデアがありません。

もう 1 つ: UpdateSession ルーチンは、正しくログインすると正常に動作します (for ループごとに 1 回の反復のみ)。エラーは、ログアウト時に最初に発生します。次に、イテレータが狂います。私の推測では、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 回発生し、アクセス違反で終了します。そして、なぜ私はまだ混乱しています

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

トリガーします。unordered_map には有効なセッションが 1 つしかないためです。

4

2 に答える 2

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++;
} 
于 2012-09-11T23:32:41.167 に答える
0

erase を使用すると、 iterator が無効になります。だからあなたが書くとき

itr2->second.erase(itr);

ハッシュマップのメンバーを指しなくなったため、UpdateSessions使用できなくなりました。itrしたがって、次の行delete itr->second;と決定的にループの繰り返しの++itr両方がエラーです。最初の問題は簡単に修正できます。削除と消去の順序を入れ替えるだけです

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

2 番目の問題は少しトリッキーです。基本的には、ループを次のように書き直す必要があります。

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 はイテレータの前の値を取得します。

于 2012-09-08T07:33:46.450 に答える