我试图找到一个段错误背后的罪魁祸首。我的调试器告诉我,错误所在的变量没有数据。每隔10秒,我的C ++代码中会运行一个小脚本。它确实"垃圾收集"并删除一些"会话"那可能已经死了。 为了有效地执行此操作,我使用时间戳 - 上次访问数据的时间。如果数据超过10秒,那就死了。有一个keepalive命令在客户端上每4秒触发一次。
为了执行此GC,我循环遍历std :: unordered_map并从存储为该对中的值的时间中减去自纪元以来的当前时间。如果时间太大,我将它添加到一个std :: vector,它包含要删除的键(是的,我知道它可以被优化以跳过这一步)。
我遇到的问题是它第一次循环正确。然而,此后,我得到一个段错误,它指向迭代器值大于地图的大小。 只需切换回标准的std :: map就可以解决整个问题!
我将附上完成所有这一切的功能。所有代码均可在http://github.com/yash101/DrawingPad
处获得现在,代码[{sourcedir} /source/Session.cxx]:
void SessionHost::cron()
{
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
if(DEBUG)
{
std::cout << "Cron has started!" << std::endl;
}
while(!locky_thingy.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)))
{}
int timethrough = 0;
std::vector<std::string> del;
for(std::map<std::string, long>::iterator ite = timestamp.begin(); ite != timestamp.end(); ++ite)
{
timethrough++;
std::cout << "Time through: " << timethrough << std::endl;
std::string curkey = ite->first;
long curval = ite->second;
std::cout << "Key: " << curkey << std::endl;
if(DEBUG)
{
std::cout << "Checking " << curkey << " with old ts of " << curval << std::endl;
}
u_int64_t curtm = std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now().time_since_epoch()).count();
if(DEBUG)
{
std::cout << "Current time: " << curtm << std::endl;
}
if(curtm - curval > SESSION_TIMEOUT)
{
if(DEBUG)
{
std::cout << "Deleted session handle: [" << curkey << "]" << std::endl;
}
del.push_back(curkey);
}
else
{
if(DEBUG)
{
std::cout << "Kept back session handle: [" << curkey << "]" << std::endl;
}
}
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
}
locky_thingy.unlock();
}
}
答案 0 :(得分:7)
你有:
for(std::map<std::string, long>::iterator ite = timestamp.begin();
ite != timestamp.end(); ++ite)
{
// ...
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]); // <--
// ...
}
}
在unordered_map
中,擦除可以使迭代器无效。因此,在您遍历时无法擦除 - 尝试提出不同的算法。 (我假设您的问题的某些版本涉及timestamp
为unordered_map
- 尽管您的代码中没有此类型的引用。)
答案 1 :(得分:1)
我认为错误就在这里
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
} // <---------------- this is the end of the iterator loop
它应该在for循环之前向上移动,因此它不会失效。
} // <---------------- this is the end of the iterator loop
for(unsigned int i = 0; i < del.size(); i++)
{
timestamp.erase(del[i]);
data.erase(del[i]);
std::cout << "Erasing: " << del[i] << std::endl;
}
如果data.erase是向量,则它也可能有错误。
如果您有需要擦除的矢量,则应标记记录并使用
data.erase(std::remove_if(data.begin(), data.(end), CheckMark));
remove_if将所有有效数据移动到数据的开头,擦除然后从最后一次有效之后擦除。