Почему итераторы c ++ вектора перед позицией стирания также становятся недействительными в visual studio? - PullRequest
0 голосов
/ 25 января 2019
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!"

Я видел, что в некоторых статьях говорится, что «итераторы до стирания сохраняют свою силу, только итераторы после стирания становятся недействительными».
Но поскольку я пытаюсь использовать приведенный выше код, я обнаружил, что итераторы до того, как позиция стирания также станет недействительной, я не знаю, почему. Пожалуйста, помогите!

Ответы [ 3 ]

0 голосов
/ 25 января 2019

Это должно вам помочь.

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());
}
0 голосов
/ 25 января 2019

cppreference.com говорит следующее о vector::erase:

Делает недействительными итераторы и ссылки в или после точки удаления, включая итератор end ().

Так что в вашем примере test и temp инициализируются с 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();
}
0 голосов
/ 25 января 2019
 vector<int>::iterator iter = nums.begin();
 vector<int>::iterator test = nums.begin();

 vector<int>::iterator temp = iter;

temp, iter и test указывают на один и тот же элемент.

 iter = nums.erase(temp);

Этот элемент удален. Это делает недействительными temp и test. iter однако переназначается следующему элементу.

cout << *test << " ";

Недействительный test не расплачен. Поведение не определено.

Эта ситуация воспроизводится всякий раз, когда *temp == *temp2 верно в первой итерации. В последующих итерациях iter и temp больше не указывают на первый элемент.

...