我在erase()
容器中使用class vector
方法时出现段错误。
我比较了两个向量,所以我想从其中一个中删除另一个不存在的元素。为此,我使用了迭代器和erase()
,如下所示:
#include <vector>
int main () {
std::vector<int> vector1 {6,7,5,44,3,10,9,17,1};
std::vector<int> vector2 {1,2,3,5,8};
for (std::vector<int>::iterator it (vector2.begin()); it != vector2.end(); ++it) {
bool equal (false);
for (std::vector<int>::iterator jt (vector1.begin()); jt != vector1.end(); ++jt) {
if (*it == *jt) {
equal = true;
break ;
}
}
if (!equal) {
vector2.erase(it);
}
}
return 0;
}
导致段错误的原因是删除了vector2
(8
)中的最后一个元素,因为erase()
无法成功地将迭代器从之前的end()
位置移开(不再是新的。
如何防止这种情况?我知道unordered_set
可能是此操作的适当容器,但我在vector
感兴趣。
答案 0 :(得分:3)
你无法删除:
if (!equal) {
vector2.erase(it);
}
erase
操作使it
无效,因此下一个++it
是错误。
而不是它,您可以将外循环重写为:
for (std::vector<int>::iterator it (vector2.begin()); it != vector2.end();)
并在it
循环中更改for
:
if (!equal) {
it = vector2.erase(it);
} else {
++it;
}
注意,你也可以使用 remove-erase idiom :
vector2.erase(
std::remove_if(std::begin(vector2), std::end(vector2), [&vector1](const auto& e) {
return std::find(std::cbegin(vector1), std::cend(vector1), e) == std::end(vector1);
}),
std::end(vector2)
);
这是执行此类操作的标准方法。
答案 1 :(得分:3)
正如其他人所指出的那样,问题在于擦除会使迭代器失效。但是在这里使用原始循环来进行这种操作有一个更普遍的问题。它需要大量的样板代码并且容易出错。您可以使用标准算法来避免这些陷阱。
std::vector<int> result;
std::sort(vector1.begin(), vector1.end());
std::sort(vector2.begin(), vector2.end());
std::set_difference(
vector2.begin(),
vector2.end(),
vector1.begin(),
vector1.end(),
std::back_inserter(result));
答案 2 :(得分:2)
问题是擦除后你的迭代器失效了。改变这个:
vector2.erase(it);
到此:
it = vector2.erase(it);
这将是解决问题的一步。检查docs,您会看到返回值是下一个有效的迭代器。