为什么在擦除位置之前的矢量的 c++ 迭代器在 Visual Studio 中也失效

Why c++ iterators of vector before erase position are also invalidated in visual studio?

本文关键字:Visual 迭代器 Studio 失效 c++ 位置 擦除 为什么      更新时间:2023-10-16
int removeDuplicates(vector<int>& nums) {
    vector<int>::iterator iter = nums.begin();
    vector<int>::iterator test = nums.begin(); //used to test
    while (nums.begin() != nums.end())
    {       
        vector<int>::iterator temp = iter;
        vector<int>::iterator temp2 = ++iter;
        if (temp2 == nums.end()) break;
        if (*temp == *temp2)
        {           
            iter = nums.erase(temp);
            cout << *test << " ";  //test here, error happen
        }
    }
    return nums.size();
}
int main()
{
    vector<int> test = { 1,1,2,2,4,5,6,6 };
    int result = removeDuplicates(test);
}

错误消息:"vector iterator not dereferencable!"

我看过一些文章说"擦除位置之前的迭代器保持有效,只有擦除位置后的迭代器变得无效。
但是当我尝试使用上面的代码时,我发现擦除位置也变得无效之前的迭代器,我不知道为什么。请帮忙!

 vector<int>::iterator iter = nums.begin();
 vector<int>::iterator test = nums.begin();
 vector<int>::iterator temp = iter;

tempitertest指向同一个元素。

 iter = nums.erase(temp);

该元素将被擦除。这使temptest无效。 但是,iter被重新分配给下一个元素。

cout << *test << " ";

无效的test是不可竖立的。行为是不确定的。

只要在第一次迭代中*temp == *temp2为真,就会重现这种情况。在以后的迭代中,itertemp 不再指向第一个元素。

这应该对您有所帮助。

int removeDuplicates(std::vector<int>& nums) 
{
    for (auto iter = nums.begin(); iter != nums.end(); /* DO NOT INCREMENT */)
    {
        if (std::find(iter + 1, nums.end(), *iter) != nums.end())
        {
            iter = nums.erase(iter);
        }
        else
        {
            ++iter;
        }
    }
    return static_cast<int>(nums.size());
}

cppreference.com 对vector::erase说了以下内容:

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

所以在你的例子中,testtemp都是用nums.begin()初始化的。当您擦除temp 时,这将temp无效。因此,您需要确保重新初始化temp,或者保留已删除元素的副本以供以后使用。

那么像这样更改代码怎么样:

int removeDuplicates(vector<int>& nums) {
    vector<int>::iterator iter = nums.begin();
    vector<int>::iterator test = nums.begin(); //used to test
    while (nums.begin() != nums.end())
    {
        vector<int>::iterator temp = iter;
        vector<int>::iterator temp2 = ++iter;
        size_t dist = std::distance(nums.begin(), temp);
        if (temp2 == nums.end()) break;
        if (*temp == *temp2)
        {
            iter = nums.erase(temp);
            test = nums.begin();
            test += dist;
            cout << *test << " ";  //test here, error happen
        }
    }
    return nums.size();
}