vector :: erase()会改变位置吗?

时间:2012-09-04 19:18:00

标签: c++ vector erase

这是我的问题,我有一个双向量,我需要在一定条件下消除它们中的一些。这是一个代码示例:

 vector <double> appo;
 for(int i=0;i<appo.size();i++){
       for(int j=i+1;j<appo.size();j++){
         if( condition(appo[i],appo[j]) ){
           appo.erase(appo.begin()+j);
           j--;
         }
       }
    }

因为在擦除()之后我的大小减少了1并且所有元素左移左移,所以减少j是正确的吗?

好的我决定不使用removeif,因为它是一个小程序,我现在不关心性能,但是我得到了分段错误。 这是代码:

vector <double> *point;
for(int i=0;i<point->size();i+=3){
     for(int j=i+3;j<point->size();j+=3){
       if(distance((*point)[i],(*point)[i+1],(*point)[i+2],(*point)[j],(*point)[j+1],(*point)[j+2]) < treshold){
         point->erase(point->begin()+j,point->begin()+j*3);
         j-=3;
       }
     }
  }

point是一个坐标向量,如(x1,y1,z1,x2,y2,z3,...,xn,yn,zn)。 有什么想法吗?

1 个答案:

答案 0 :(得分:6)

递减j是正确的,因为在删除索引j处的元素后,之前位于j+1的元素现在位于j,因此您需要使用相同的j值重复循环。减少它会产生这种效果,因为循环本身会增加它。

您还可以考虑使用迭代器而不是索引:

vector<double>::iterator j = appo.begin() + i + 1;
while (j != appo.end()) {
    if (condition(appo[i], *j)) {
        j = appo.erase(j);
    } else {
        ++j;
    }
}

完成后,您也可以使用i的迭代器。

正如“eq-”在评论中所说,有一种标准算法可以帮助你。在你的可用性方面,你可以选择它是否更喜欢循环,但它通常更有效,因为反复调用“擦除”每次一步一步地清洗每个元素,而remove_if跟踪“读取位置”和“写入位置”,因此它只复制每个元素一次。

appo.erase(
    appo.remove_if(
        appo.begin() + i + 1,
        appo.end(),
        ShouldRemove(appo[i])
    ),
    appo.end()
);

在C ++ 03中,您必须定义ShouldRemove,类似于:

struct ShouldRemove {
    double lhs;
    ShouldRemove(double d) : lhs(d) {}
    bool operator()(double rhs) {
        return condition(lhs, rhs);
    }
};

在C ++ 11中,您可以使用lambda而不是ShouldRemove:

appo.erase(
    appo.remove_if(
        appo.begin() + i + 1,
        appo.end(),
        [&](double d) { return condition(appo[i], d); }
    ),
    appo.end()
);

您还可以使用std::bind1stboost::bind(在C ++ 03中)或std::bind(在C ++ 11中)使用一些选项,但要正确理解这些选项非常棘手。