为什么我会通过地图插入获得分段错误

时间:2009-01-27 21:32:03

标签: c++

我想在地图中插入一个pair< string, vector<float> >,首先它可以工作,但是在几个循环之后,它不能再插入并给我一个分段错误。任何人都可以说明理由吗?

顺便说一句:我首先读取一个文件并生成地图(大约200,000个元素),然后我读取另一个文件并更新旧地图。更新步骤时发生错误。

有人可以帮我处理上面提供的信息吗?非常感谢

代码很长.....我只是擦掉以前的密钥,然后插入一个新密码,看起来并不复杂......但是让我发疯了......你能猜到这里发生了什么吗?

非常感谢您的所有答案!我发现它确实是解决问题的好地方。再次感谢,我将尝试简化我的代码并在今天或明天将其添加到此处。

更新:我使用了MSN的代码并且它有效,非常感谢你在没有看到我的代码的情况下解决了我的问题......也非常感谢其他善良的人们!但是,我只能选择一个作为答案。

8 个答案:

答案 0 :(得分:5)

您是否使用名为erase()的迭代器进行插入?或以任何方式使用该迭代器?调用erase(p)后,p无效。

答案 1 :(得分:2)

如果没有更多信息,说起来并不容易,但是你要插入什么?难道只是你内存不足吗?虽然,我认为普通的C ++会在这种情况下抛出异常,你是否在堆栈上使用任何自定义分配器,malloc或数组,这些都可能超支?

也许一段描述你所做的事情的代码可能有助于确定问题的原因。

答案 2 :(得分:2)

  你能猜到这里发生了什么吗?

你以某种方式滥用记忆。

在C ++中有一种很多的方法可以做到这一点!

我建议运行一种特定于平台的调试器来检测这个问题,而不是猜测,而不是读取代码,例如valgrind

您的另一种选择是缩小问题:只需几行代码即可重现问题,然后您可以将其发布给人们查看。

答案 3 :(得分:1)

如果您修改数据结构中已有元素的键,或者您的比较函数错误,这会误导搜索算法,则很容易发生。

如果您可以检测哪个具体插入操作导致seg.fault,则尝试使用调用compare函数的值调试/记录。

或者,您应该在错误插入之前打印地图的内容,这些键可能不是有序的。

答案 4 :(得分:1)

有问题的类型是pair<string, vector<float> >。您将在每个插页上复制该对。如果字符串或向量很大,那么你可能会耗尽内存。

编辑:要修复内存不足,您可以更改键值对的插入方式:

pair<map::iterator, bool> insert_result= map.insert(make_pair(name, vector<float>());
if (insert.second) { insert_result.first->second.swap(vector_read_in); }

这将确保您不复制内存,只移动它。

答案 5 :(得分:0)

请发布一些代码,你不能指望我们在猜测工作中调试你的问题。

...但不管怎么说还是刺了一下:)还有什么编译器和系统你在做什么呢?

如果您正在循环中读取数据,则可能会耗尽堆栈空间,从而导致seg错误。

如果您发布一些代码,请编辑我的答案。

答案 6 :(得分:0)

请记住,如果您循环浏览地图,找到要删除的内容,请保存密钥以便以后删除。如果在迭代时删除,则存在使迭代循环无效的风险。

std::map<string, vector<float> >::iterator iter = my_map.begin();
while (iter != my_map.end()) {
  if (somethingBadAboutItem(iter)) {
    my_map.erase(iter);   // this can mess up my_map iteration above 
                          // and cause bad data access later
  }
  ++iter;
}

相反,请尝试

std::map<string, vector<float> >::iterator iter = my_map.begin();
std::vector<string> keys_to_delete;
while (iter != my_map.end()) {
  if (somethingBadAboutItem(iter)) {
    keys_to_delete.push_back(iter->first);
  }
  ++iter;
}

for (std::size_t i = 0; i < keys_to_delete.size(); ++i) {
  iter = my_map.find(keys_to_delete[i]);
  my_map.erase(iter);
}

我很感兴趣,如果其他人找到比这更优雅的东西,但这是我的首选技术。

答案 7 :(得分:0)

比尔:你有没有试过这样的事情:

for(std::map<string, vector<float> >::iterator iter = my_map.begin(); iter != my_map.end();) {
    if(somethingBadAboutItem(iter)) {
        my_map.erase(iter++);
    } else {
        ++iter;
    }
}

关键是在删除时后递增迭代器,因此在递增时它仍然有效,但是你擦除(并因此使其无效)指向前一项的副本。

我不确定这种技术是否适用于所有STL容器;我不记得所有的失效规则(例如,似乎不太适用于矢量,但你通常最好使用remove_if来处理那些非平凡的尺寸)但它应该适用于地图。