std :: unordered_map中可能存在的错误

时间:2014-11-03 01:56:14

标签: c++ c++11 segmentation-fault unordered-map

我试图找到一个段错误背后的罪魁祸首。我的调试器告诉我,错误所在的变量没有数据。每隔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();
    }
}

2 个答案:

答案 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中,擦除可以使迭代器无效。因此,在您遍历时无法擦除 - 尝试提出不同的算法。 (我假设您的问题的某些版本涉及timestampunordered_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将所有有效数据移动到数据的开头,擦除然后从最后一次有效之后擦除。