【问题标题】:Erase function of the std::vectorstd::vector 的擦除功能
【发布时间】:2019-09-21 18:30:57
【问题描述】:

我有一个std::vector 和一个指向向量中元素的迭代器。我的问题是如何从向量中删除元素并保留迭代器?

我尝试使用第二个迭代器来查找我要删除的特定元素,并在使用擦除功能擦除它后,第一个迭代器变得无效。

【问题讨论】:

  • 使用索引而不是迭代器。
  • 那么使用迭代器是不可能的?
  • 好吧,erase[i]n 在擦除点或之后验证迭代器和引用”。
  • 谢谢,现在我明白为什么这不起作用了

标签: c++ vector iterator erase


【解决方案1】:

我有一个 std::vector 和一个指向向量中元素的迭代器。我的问题是如何从向量中删除元素并保留迭代器?

请注意,当一个元素被删除时,没有迭代器可以指向它,因为它不再存在。因此,要引用它的位置,通常的做法是使用 erase() 方法返回的迭代器。这允许使用insert() 方法,该方法将在先前擦除的对象的位置放置一个值。 使用一个迭代器,只需使用这个:

auto loc_after = v.erase(iter);  // since the element has been erased loc_after points to the position the erased element had

我尝试使用第二个迭代器来查找我要删除的特定元素,并在使用擦除功能擦除它后,第一个迭代器变得无效。

在有两个迭代器的情况下,可以通过首先擦除物理上最后一个迭代器来轻松擦除元素,因为较早的迭代器不会失效。这被封装在一个函数中。返回的迭代器指向超过“第一个”迭代器的位置,而不管第一个和第二个迭代器之间的顺序如何。

#include <vector>
#include <iostream>

// This returns an iterator positioned after where  first_iter was before being erased
// this allows the insert(pos, val) method to insert a value in the the location just prior to pos
std::vector<int>::iterator second_iterator_loc(std::vector<int>& v, std::vector<int>::iterator first_iter, std::vector<int>::iterator second_iter)
{
    std::vector<int>::iterator iter;
    if (first_iter < second_iter)
    {
        v.erase(second_iter);
        iter = v.erase(first_iter);
    }
    else if (second_iter < first_iter)
    {
        auto dist = first_iter - second_iter;
        v.erase(first_iter);
        iter = v.erase(second_iter) + dist - 1;
    }
    else
    {
        ;// handler in case both iterators point to the same object
    }
    return iter;
}

int main()
{
    std::vector<int> v{ 1,2,3,4,5 };
    std::vector<int> v2 = v;

    std::vector<int>::iterator iter1 = v.begin() + 1; // points to 2 in v
    std::vector<int>::iterator iter2 = v.begin() + 3; // points to 4 in v

    std::vector<int>::iterator iter;
    iter = second_iterator_loc(v, iter1, iter2);
    v.insert(iter, 9);  // inserts a 9 in the previous location of the "first" iterator (where "2" was)
    for (auto x : v)
        std::cout << x << '\n'; // prints: 1 9 4 5

    v = v2;
    iter1 = v.begin() + 3; // reverse iterator positions
    iter2 = v.begin() + 1;

    iter = second_iterator_loc(v, iter1, iter2);
    v.insert(iter, 9);  // inserts a 9 in the previous location of the "first" iterator (where "4" was)
    for (auto x : v)
        std::cout << x << '\n'; // prints: 1 3 9 5

}

【讨论】:

  • 感谢您的回答和示例。 @Ton van den Heuvel 在对他的回答的评论中建议了这一点,但是“问题是我有 2 个迭代器指向 2 个元素,第一个需要最后删除,因为我需要保持那个位置。如果第二个是在第一个之前,我向后删除它们,我将失去第一个的位置”。
  • 我已经编辑了答案,将细节放在一个函数中来解决这个问题。
  • 这真的很有趣,不知道你可以做first_iter-second_iter之类的事情来存储第一个迭代器与第二个迭代器的位置。我了解您为避免在擦除 2 个迭代器后丢失迭代器的位置所做的工作。这正是我想做的,感谢您的回答和实施。
【解决方案2】:

我的问题是如何从向量中删除一个元素并保留迭代器?

您不能使用std::vector::iterator。迭代器将通过擦除元素而失效。

但是您可以通过编写自己的迭代器类来实现这一点,该类存储指向向量和索引的指针。

【讨论】:

  • 我真的不知道如何编写自己的迭代器类,我将只使用@melpomene 建议的索引,因为至少对我来说这似乎是实现这一目标的最简单方法。 .感谢您的回答,我现在明白迭代器将通过擦除元素而失效。
【解决方案3】:

std::vector::erase 将使擦除元素处或之后的所有迭代器无效:

在该点处或之后使迭代器和引用无效 擦除,包括 end() 迭代器。

但是,erase 将返回一个迭代器,该迭代器指向最后一个被移除元素之后的元素。也许这足以满足您的用例?

【讨论】:

  • 我在发布之前也读过,但对我没有多大帮助,因为我需要先删除第二个迭代器,所以在我删除它的那一刻我会丢失第一个。但这是一个非常好的观察结果,在其他情况下可能有用
  • 如果您有多个迭代器指向需要擦除的元素,则在擦除时向后迭代它们,这将起作用。规范的方法是将std::removestd::vector::erase 结合使用。参见示例:en.cppreference.com/w/cpp/algorithm/remove
  • 问题是我有 2 个迭代器指向 2 个元素,第一个需要最后删除,因为我需要保持那个位置。如果第二个在第一个之前并且我向后删除它们,我将失去第一个的位置。
  • 在这种情况下,一种方法是在擦除之前记录所需元素的索引,并根据为擦除元素校正的旧索引计算新的迭代器。
  • 除了反复试验,我不知道任何策略。阅读可用的内容也是值得的 (en.cppreference.com/w/cpp/algorithm)。下面的演讲让我大开眼界,让我了解在代码中使用算法而不是 for 循环:youtube.com/watch?v=qH6sSOr-yk8,推荐。
猜你喜欢
  • 2011-07-17
  • 2018-12-05
  • 2011-10-24
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 2022-10-24
  • 2011-09-30
相关资源
最近更新 更多