为啥在Visual Studio中擦除位置之前矢量的c ++迭代器也无效?

Posted

技术标签:

【中文标题】为啥在Visual Studio中擦除位置之前矢量的c ++迭代器也无效?【英文标题】:Why c++ iterators of vector before erase position are also invalidated in visual studio?为什么在Visual Studio中擦除位置之前矢量的c ++迭代器也无效? 【发布时间】:2019-01-25 15:01:05 【问题描述】:
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!" 我看过一些文章说“擦除位置之前的迭代器保持有效,只有擦除位置之后的迭代器变得无效。” 但是当我尝试使用上面的代码时,我发现擦除位置之前的迭代器也变得无效,我不知道为什么。请帮忙!

【问题讨论】:

向量的内容是什么?您可以尝试创建一个minimal reproducible example 来展示给我们看吗?也请阅读how to ask good questions,以及this question checklist。 如果我没看错,你只会删除第一个元素,所以永远不会有“擦除位置之前的迭代器” 关于可能发生的事情的提示,如果nums[0] == nums[1] 会怎样?然后你删除 nums[0] 并取消引用一个迭代器到(现在删除的元素)nums[0] 感谢您的快速回答,您是对的,我明白了。 【参考方案1】:
 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 不再指向第一个元素。

【讨论】:

【参考方案2】:

这应该对你有帮助。

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

【讨论】:

【参考方案3】:

cppreference.com 对vector::erase 说如下:

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

因此,在您的示例中,testtemp 均使用 nums.begin() 进行初始化。当您擦除 temp,这无效 temp。因此,您需要确保 temp 被重新初始化,或者您保留 erased 元素的副本以供以后使用。

那么像这样改变你的代码怎么样:

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

【讨论】:

以上是关于为啥在Visual Studio中擦除位置之前矢量的c ++迭代器也无效?的主要内容,如果未能解决你的问题,请参考以下文章

在本机反应中擦除 AsyncStorage

在fabric js中擦除iText时显示光标线代替擦除的字符

在单个链表线程中擦除和插入是不是安全?

从向量中擦除指针

在 std::vector 中擦除、调试、发布

击败从内存中擦除 PE