Проблема с обработкой вектора C++ STL

153
27 декабря 2018, 07:40

Собственно суть проблемы:

При выполнении выдает ошибку:

Expression: vector iterator not incrementable. For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.

Проблема в этой строке : arr.erase(it);
Как исправить эту ошибку?

void DeleteZeros(std::vector<int>&arr)
{
    for (std::vector<int>::iterator it = arr.begin(); it != arr.end(); ++it)
    {
        if (*it == 0)
        {
            arr.erase(it);
        }
        else
        {
            std::cout << "asdasdasd"<< std::endl;
        }
    }
}

Код:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
//using namespace std;

void MakeArr(std::vector<int>&arr)
{
    for (int i = 0; i < arr.size(); i++)
    {
        arr[i]= rand() % 10;
    }
}
void show_vector(std::vector<int>&a)
{
    for (std::vector<int>::iterator it = a.begin(); it != a.end(); ++it)
        std::cout << *it<<" ";
}

int*GetFreq1(int*arr, int size)
{
    int*FreqArr=new int[size];

    for (int i = 0; i < size; i++)
    {
        int Count = 1;
        for (int j = i + 1; j < size; j++)
        {
            if (arr[i] == arr[j])
            {
                Count++;
                FreqArr[j] = 0;
            }
        }
        if (FreqArr[i] != 0)
        {
            FreqArr[i] = Count;
        }
    }
    std::cout << "\n Frequency of All the Elements in this Array are : \n" << std::endl;
    for (int i = 0; i < size; i++)
    {
        if (FreqArr[i] != 0)
        {
            std::cout << arr[i] << "occurs" << FreqArr[i] << "times" << std::endl;
        }
    }
    return FreqArr;

}
void DeleteZeros(std::vector<int>&arr)
{
    for (std::vector<int>::iterator it = arr.begin(); it != arr.end(); ++it)
    {
        if (*it == 0)
        {
            arr.erase(it); //iterator is not incrementable
            //std::cout << "blyaa";
        }
    }
}
int main()
{
    int n;
    std::cout << "input count of elements :";
    std::cin>>n;
    std::vector<int>arr(n);
    std::vector<int>n_i(n);
    MakeArr(arr);
    show_vector(arr);
    std::sort(arr.begin(), arr.end()); //variazijnyj ryad
    std::cout <<std::endl<<"Sorted Arr :" << std::endl;
    show_vector(arr);
    //n_i=getFreq(arr, n);      
    int*sss = new int[n];
    int*atatat = new int[n];
    for (int i = 0; i < arr.size(); i++)
    {
        atatat[i] = arr[i];
    }
    sss = GetFreq1(atatat, n);
    for(int i=0;i<arr.size();i++)
    {
        n_i[i] = sss[i];
    }
    //std::unique(arr.begin(), arr.end());// building a table
    std::cout << "\n N-i table: " << std::endl;
    show_vector(n_i);
    DeleteZeros(n_i);
    show_vector(n_i);

    system("pause");
    return 0;
}
Answer 1

Вообще-то у вас при выполнении arr.erase(it) итератор инвалидируется, и продолжать работать с ним нельзя, о чем так и пишется в описании erase():

Invalidates iterators and references at or after the point of the erase, including the end() iterator.

Для понимания - представьте ситуацию, когда вы удаляете единственный элемент вектора - сразу после этого, даже если никакого переноса элементов не будет, вы получите, что итератор уже указывает за массив - в arr.end(). А вы собираетесь его еще и увеличить, а потом сравнить с arr.end() - во-первых, он будет не равен, и вы получаете бесконечный цикл, во-вторых, начинаете проверять элементы все дальше и дальше за границами массива... Так понятнее?

Кроме того, erase() по одному элементу - процедура дорогостоящая.

Так что замените некорректное решение на, например, такое - с использованием стандартного алгоритма remove():

void DeleteZeros(std::vector<int>&arr)
{
    arr.erase(remove(arr.begin(),arr.end(),0),arr.end());
}
Answer 2

Это не ответ на заданный вами вопрос, но очень хотелось отметить, что нужно выбирать путь проще при написании кодов, используя больше инструментов, предаставленных стандартом. Вот, например, можно упростить весь ваш код до такого:

int n;
std::cout << "input count of elements : ";
std::cin>>n;
std::vector<int>arr(n);
for (int& i : arr)
    i = rand() % 10;
std::map<int, int> m_i;
for (const int i : arr) {
    std::cout << i << ' ';
    m_i[i]++;
}
std::cout << std::endl;
std::cout << "\n Frequency of All the Elements in this Array are : \n\n";
for (auto p : m_i)
     std::cout << p.first << " occurs " << p.second << " times\n" ;
std::cout << " N-i table: \n";
for (auto p : m_i)
    std::cout << p.second <<' ';

Без всяких сложностей с определениями функций и фигурирования массивов. Тут конечно можно еще уменьшить количество строк, если использовать стандартные альгоритмы и лямбда выражения, но такой вариант не хуже...

Answer 3

Само собой у вас выдает ошибку, смотрите сюда:

for (std::vector<int>::iterator it = arr.begin(); it != arr.end(); ++it)
{
    if (*it == 0)
    {
        arr.erase(it);

видите, вы удаляете итератор, а что потом? А потом вы берете его, и увеличиваете в for, делаете ++it

Чтобы исправить сделайте так (проверено):

void DeleteZeros(std::vector<int>&arr)
{
   for (std::vector<int>::iterator it = arr.begin(); it != arr.end();)
   {
       if (*it == 0)
       {
          arr.erase(it);
       }
       else
       {
          ++it;
       }
   }
}

Таким образом после удаления for будет проверять можно ли увеличивать итеротор (тобишь не указывает ли он на конец). Правда если будете удалять несколько, а не один, это все равно приведет к проблеме.

READ ALSO
Как определить по какому мешу кликнули внутри класса APawn?

Как определить по какому мешу кликнули внутри класса APawn?

Есть ли в классе Pawn функционал для отслеживания событий мыши, клавиатуры по конкретному мешу внутри Pawn?

185
Как правильно написать этот код с шаблонами?

Как правильно написать этот код с шаблонами?

При компиляции выводиться ошибка, вот такая

160
C/C++, GetLastError() и errno()

C/C++, GetLastError() и errno()

Я бы хотел разобраться в том, каким образом названные функции реализуют сохранение информации о последней возникшей ошибке в текущем вызывающем...

157
Работа с wav файлами в с++

Работа с wav файлами в с++

Необходимо создать wav файл в котором будут сохранены дорожки нескольких wav файлаМожно посоветовать и библиотеку которая занимается этим...

170