简体   繁体   English

访问迭代器指向的列表元素

[英]Accessing list element pointed by an iterator

The natural answer would be to dereference the iterator and get the value. 自然的答案是取消引用迭代器并获取值。 However, I'm stuck at using VC++ 2010 which doesn't allow dereferencing the list iterator (or does it?) I'm confused because, at one point, I need to dereference two list iterators and compare their values using: (*it) == (*it2) The program crashes with an error, only due to this line. 但是,我坚持使用VC ++ 2010,它不允许解除引用列表迭代器(或者是吗?)我很困惑,因为在某一点上,我需要取消引用两个列表迭代器并使用它们比较它们的值:(*它)==(* it2)程序因错误而崩溃,只是由于这一行。 I'm also dereferencing the iterator in a statement: printf("%d\\n", (*it)); 我也在一个语句中取消引用迭代器:printf(“%d \\ n”,(* it)); This works perfectly fine though. 这虽然工作得很好。 So, is there any way to access an element without dereferencing or using a cliext::list. 那么,有没有办法在不解除引用或使用cliext :: list的情况下访问元素。

for (it=sList.begin(); it != sList.end(); it++)
{
    for (it2=it; it2 != sList.end(); it2++)
    {
        it2++;
        if ((*it) == (*it2))
        {
           sList.erase(it, it2);
        }
        it2--;
    }
}

The error I get is: 我得到的错误是:

Debug Assertion Failed 调试断言失败

Expression: list iterator not dereferencable 表达式:列出迭代器而不是dereferencable

Surprisingly the same code runs without a problem when compiled on DevC++ (MinGW) 令人惊讶的是,在DevC ++(MinGW)上编译时,相同的代码运行没有问题

You can in fact dereference list iterators. 实际上,您可以取消引用list迭代器。 If you couldn't, your comparison code wouldn't have even compiled. 如果你不能,你的比较代码甚至不会编译。 Most likely you're accidentally dereferencing an end iterator though rather than a valid one, causing the crash. 很可能你不小心取消引用了一个end迭代器,而不是一个有效的迭代器,导致崩溃。 Without more code it's hard to make further observations. 没有更多的代码,很难进一步观察。

EDIT: I can't make out quite what it is you're trying to do. 编辑:我无法弄清楚你正在尝试做什么。 The code you've written erases all the elements between two equal elements. 您编写的代码将擦除两个相等元素之间的所有元素。 I'll assume you're actually trying to remove all the duplicate elements, and that sorting the list first for performance isn't a concern/option. 我假设您实际上是在尝试删除所有重复元素,并且首先对列表进行排序以获得性能不是问题/选项。

EDIT2: I saw in a comment below you really want to delete the range. 编辑2:我在下面的评论中看到你真的想要删除范围。 Updated my code. 更新了我的代码。

Then try something like this: 然后尝试这样的事情:

for (it=sList.begin(); it != sList.end(); ++it)
{
    it2 = it;
    ++it2;
    while(it2 != sList.end())
    {
        if ((*it) == (*it2))
        {
           it = it2 = sList.erase(it, it2);  // Reset it as well since it will be blown away. It'll still point to the same value it did before though.
        }
        else
            ++it2;
    }
}

"select" Isn't Broken. “选择”不是破碎。

It is rare to find a bug in the OS or the compiler, or even a third-party product or library. 很难在操作系统或编译器中找到错误,甚至是第三方产品或库。 The bug is most likely in the application. 该错误最有可能在应用程序中。 - from The Pragmatic Programmer - 来自实用程序员

It's highly likely due to your problem, not MS. 这很可能是由于你的问题,而不是MS。 Make it sure that your iterators are not invalidated while you are using them. 确保您的迭代器在使用它们时不会失效 You could accidentally erase the element which invalidate the iterator. 您可能会意外删除使迭代器无效的元素。 Check this thread: What is the lifetime and validity of C++ iterators? 检查这个线程: C ++迭代器的生命周期和有效性是什么? and Good Luck! 还有祝你好运! :) :)

UPDATE: 更新:

As I mentioned earlier, you are invalidating your iterators by erasing them in the middle of the loop. 正如我前面提到的,你通过在循环中间擦除它们来使你的迭代器失效。 See my code below to do it properly. 请参阅下面的代码以正确执行此操作。

std::list<int>::iterator EraseElements(std::list<int>& sList, std::list<int>::iterator start)
{
    for (std::list<int>::iterator itor1 = start; itor1 != sList.end(); ++itor1)
    {
        std::list<int>::iterator itor2(itor1);
        ++itor2;

        for ( ; itor2 != sList.end(); ++itor2)
        {
            if ((*itor1) == (*itor2))
            {
                return sList.erase(itor1, itor2);
            }
        }
    }

    return sList.end();
}


void main()
{
    // Test
    list<int> sList;
    sList.push_back(1);

    // elements will be erased
    sList.push_back(2);
    sList.push_back(3);
    //
    sList.push_back(2);

    sList.push_back(4);
    sList.push_back(5);

    // elements will be erased
    sList.push_back(6);
    sList.push_back(7);
    //
    sList.push_back(6);


    list<int>::iterator next = sList.begin();
    while (next != sList.end())
    {
        next = EraseElements(sList, next);
    }

    // It will print 1 2 4 5 6
    for (std::list<int>::const_iterator itor = sList.begin(); itor != sList.end(); ++itor)
    {
        cout << *itor << endl;
    }
}

Its surely your code. 它肯定是你的代码。 It has two problems as far as I can see. 就我所见,它有两个问题。 Checkout the comments. 查看评论。

for (it2=it; it2 != sList.end(); it2++)
    {
        it2++;
            // there is no guarantee that it2 will now be valid
            // it should be validated again
        if ((*it) == (*it2))
        {
            // you should not modify the list here.
            // this will invalidate your iterators by default.
           sList.erase(it, it2);
        }
        it2--;
    }

Try this instead: 试试这个:

for (it=sList.begin(); it != sList.end(); it++)
{
    for (it2=sList.end()-1; it2 != it+1; it2--)
    {
        if ((*it) == (*it2))
        {
            it = sList.erase(it, it2)-1;
            break;
        }
    }
}

This new version avoids two errors in the original version of the code. 此新版本避免了原始版本代码中的两个错误。 First, the code now properly handles the edge conditions of the inner for loop. 首先,代码现在正确处理内部for循环的边缘条件。 In the original code, the for loop allowed it2 to go up to sList.end()-1 , but then the next line incremented it to sList.end() on the last iteration. 在原始代码中,for循环允许it2上升到sList.end()-1 ,但是下一行在最后一次迭代时将其递增到sList.end() The next line then dereferenced this (invalid) iterator which is one past the last value of the list (because that's what end returns, it's not an iterator to the last value of the list). 然后下一行取消引用这个(无效的)迭代器,它是一个超过列表最后一个值的迭代器(因为那是end返回的,它不是列表最后一个值的迭代器)。

Second, calling erase invalidates any iterators pointing to any of the values erased (which in this case would including any iterators from it to it2-1 ). 第二,呼叫erase无效指向任何擦除的值(在这种情况下将包括来自任何迭代的任何迭代itit2-1 )。 By starting at the end of the list and working our way forward, we no longer have to continue iterating when we find the value, and can break from the inner loop once we find it. 通过从列表的末尾开始并向前推进,我们不再需要在找到值时继续迭代,并且一旦找到它就可以从内循环中break erase returns an iterator to the next element in the list after the elements deleted (which would be the next element we want to try for it ). erase返回一个迭代到下一个元素在列表中的元素删除后(这是我们想尝试下一个元素it )。 But since the for loop increments it , we subtract 1 from what's returned by erase so that it points to the right element once it's incremented at the beginning of the next loop iteration. 但是由于for循环递增it ,我们从erase返回的值中减去1,这样一旦它在下一个循环迭代开始时递增, it指向右边的元素。 (Note that in the case that it points to the first element, we actually temporarily set it to point an element before the beginning of the list; however, this is only temporary and we don't dereference the iterator while it's pointing outside the list). (注意,在it指向第一个元素的情况下,我们实际上暂时将其设置为在列表开头之前指向一个元素;但是,这只是临时的,当它指向列表外时我们不会取消引用迭代器)。

Note that this preserves the original behavior of the code for the case 0 2 3 4 5 1 6 7 8 0 9 10 11 1 . 请注意,这保留了案例代码的原始行为0 2 3 4 5 1 6 7 8 0 9 10 11 1 You haven't explicitly stated what order the deletes should occur (should the elements between 0 's be erased first, or the elements between 1 's, or do we need to add additional logic to actually erase the whole range except for the first 0 and 1 ?), but this code behaves like the original and erases the numbers in between the 0 's and ignores the fact that the 9 10 11 afterwards was original in between matching 1 's. 你没有明确说明删除应该发生什么顺序(如果首先删除0之间的元素,或者1之间的元素,或者我们是否需要添加额外的逻辑来实际擦除整个范围,除了第一个01 ?),但是这段代码的行为和原始代码一样,并且删除了0之间的数字,并且忽略了之后的9 10 11在匹配1之间是原始的事实。

It is really unclear what this code snippet or whatever code you get the error from is trying to do. 目前还不清楚这段代码片段或者你从错误中得到的代码是什么。

It appears what you want to do is for each item delete all items between it and the next matching item, or maybe it is the last matching item. 看来你想要做的就是删除它与下一个匹配项之间的所有项目,或者它可能是最后一个匹配的项目。

your inner loop iteration is double stepping from the loop increment and then incrementing again inside the loop. 你的内循环迭代是从循环增量加倍步进,然后在循环内再次递增。

your not checking if you have hit/passed the end of the list after doing the inner iteration which could lead to the crash when doing the comparison 在进行内部迭代后,你没有检查是否已经击中/通过了列表的末尾,这可能导致在进行比较时发生崩溃

after erasing you decrement it2, which then puts it before what it1 was (and is now deleted). 在擦除之后,你减少it2,然后将它放在it1之前(现在被删除)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM