从std::vector中移除时出现分割故障

Segmentation fault when removing from std::vector

本文关键字:分割 故障 std vector      更新时间:2023-10-16

我试图删除结构向量中的重复,这种重复是由结构中的qieid确定的:

struct infotable
{
  int qieid;
  int fid;
  int valid;
};

我写了一个子函数来做这个:

void erase_duplicate(vector<infotable> &info)
{
  vector<infotable>::iterator it0,it1;
  for(it0 = info.begin();it0 != info.end()-1; it0++)
  {
    //it1 = find(qieidarray1.begin(),it0,*it0);
    for(it1 = it0 +1;it1 != info.end(); it1++)
    {
      if((*it1).qieid == (*it0).qieid)
        it1 = info.erase(it1);
    }
  }
}

但是这段代码我有一些问题。当vector中struct的数量很少时,它工作得很好。但是当我在vector中有超过3000个结构体时,程序就会出错,我有:

分段故障11

显示在我的屏幕上。我知道这是一个内存访问问题,我可能会访问到我不应该接触的地方,因为向量中有很多元素。但无论如何,我可以改善我的代码,以获得更好的性能(运行更多的元素)?

您也可以使用<algorithm>函数来做,特别是std::unique

首先,按qieid排序,然后使用unique,它将"已删除"的元素移动到末尾并返回一个新的迭代器,然后您可以使用它实际擦除这些元素。

std::sort(info.begin(), info.end(), [](const infotable& a, const infotable& b) {
    return a.qieid < b.qieid;
});
auto newIt = std::unique(info.begin(), info.end(), [](const infotable& a, const infotable& b) {
    return a.qieid == b.qieid;
});
info.erase(newIt, info.end());

这将在O(n+log n)内运行,而您的原始解决方案具有O(n2)时间复杂度。就我个人而言,我更喜欢这个解决方案,特别是因为它更具表现力,所以更容易看到代码在做什么。

注意:如果你的编译器已经支持c++ 14的泛型lambdas,你可以使用[](const auto& a, const auto& b) { ... }

进一步简化表达式:

当你使用erase时,它会使迭代器失效。

for(it1 = it0 +1;it1 != info.end(); )
{
   if((*it1).qieid == (*it0).qieid)
      it1 = info.erase(it1);
   else
      it1++;
}

您可以使用std::set技巧删除副本,它可读性强,易于维护,但效率较低。

std::vector<int> r = {14,26,58,56,26,14};
std::set<int> s(r.begin(),r.end());
r = std::vector<int>(s.begin(),s.end());

您需要给std::set您自己的比较函数,以便它与您的结构一起工作。