我遇到有关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中应该只有一个有效的会话。
答案 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++;
}