【问题标题】:How to safely erase elements in a std::vector [duplicate]如何安全地擦除 std::vector 中的元素 [重复]
【发布时间】:2018-01-27 12:22:54
【问题描述】:

当我在 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 感兴趣。

【问题讨论】:

  • 执行此操作的标准方法称为erase-remove idiom
  • 如果您真的想按照您尝试的方式进行操作,我将在外循环中遍历vector1,在内循环中遍历vector 2。这样您就不会从外循环中的向量中删除并干扰迭代器的有效性。

标签: c++ c++11 vector iterator


【解决方案1】:

你不能删除喜欢:

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;
}

DEMO


注意,您也可以使用 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)
);

这是执行此类操作的标准方法。

【讨论】:

  • 谢谢!这解决了问题,我现在理解得更好了
【解决方案2】:

正如其他人指出的那样,问题在于擦除会使您的迭代器无效。但是这里有一个更普遍的问题是使用原始循环来进行这种操作。它需要大量样板代码并且容易出错。您可以使用标准算法来避免这些陷阱。

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));

【讨论】:

    【解决方案3】:

    问题是您的迭代器在擦除后无效。改变这个:

    vector2.erase(it);
    

    到这里:

    it = vector2.erase(it);
    

    这将是解决问题的一步。检查docs,您会看到返回值是下一个有效的迭代器。

    【讨论】:

      猜你喜欢
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 2011-09-30
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      相关资源
      最近更新 更多