如何安全地擦除 std::vector 中的元素
How to safely erase elements in a std::vector
当我在class vector
容器中使用erase()
方法时,我遇到了段错误。
我正在比较两个向量,所以我想从其中一个向量中删除另一个向量中不存在的元素。为此,我使用迭代器和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
感兴趣。
您不能像以下那样删除:
if (!equal) {
vector2.erase(it);
}
erase
操作会使it
无效,因此下一个++it
是错误。
取而代之的是,您可以将外部循环重写为:
for (std::vector<int>::iterator it (vector2.begin()); it != vector2.end();)
并在for
循环中更改it
:
if (!equal) {
it = vector2.erase(it);
} else {
++it;
}
演示
请注意,您也可以使用删除-擦除习惯用语:
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)
);
这是做这样的事情的标准方法。
正如其他人指出的那样,问题在于擦除会使您的迭代器无效。 但是在使用原始循环进行这种操作时,这里有一个更普遍的问题。 它需要大量样板代码并且容易出错。 您可以使用标准算法来避免这些陷阱。
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));
问题是您的迭代器在擦除后失效。更改此设置:
vector2.erase(it);
对此:
it = vector2.erase(it);
这将是朝着解决问题迈出的一步。检查文档,你会看到返回值是下一个有效的迭代器。
相关文章:
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- std::vector的包装器,使数组的结构看起来像结构的数组
- 编译器如何区分std::vector的构造函数
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 在std::vector上存储带有模板的类实例
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 为什么std::vector比数组慢
- std::vector::迭代器是否可以合法地作为指针
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 为什么std::vector和std::valarray初始化构造函数不同
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 在没有未定义行为的情况下实现类似std::vector的容器
- 如何调整 std::vector of Eigen::MatrixXd 的大小
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 如何将AERT_Allocate与 std:vector 一起使用
- 推导 std::vector::back() 的返回类型
- 如何将原始字节附加到 std::vector?
- std::vector 没有重载函数的实例与参数列表匹配
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?