#include<iostream>
#include<list>
using namespace std;
void compute(int num)
{
list<int> L;
list<int>::iterator i;
list<int>::iterator i2;
int p;
cout<<"Enter the number of numbers\n";
cin>>p;
int a;
for(int k=1;k<=p;k++)
{
cin>>a;
L.push_back(k);
}
cout<<endl;
for(i=L.begin() ; i!=L.end() ; ++i)
{
cout<<*i<<endl;
}
long int k=1;
for(i=L.begin() ; i!=L.end() ; ++i )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i2=L.erase(i);
}
k++;
}
for(i=L.begin() ; i!=L.end() ; ++i )
{
cout<<*i<<endl;
}
}
int main()
{
// int testcases, sailors;
//cin>>testcases;
//for(int i=1 ; i<=testcases ; i++)
{
// cin>>sailors;
}
//for(int i=1;i<=testcases;i++)
{
// int num;
//cin>>num;
//compute(num);
}
compute(0);
return 0;
}
Я пытаюсь стереть элементы с помощью функции L.erase () в списках. Но я получаю сообщение об ошибке
«Отладочное утверждение не удалось! …… Выражение: список итераторов не может быть увеличен», но мы МОЖЕМ увеличивать итератор, верно?
erase
делает недействительным итератор, который был передан в качестве параметра — поскольку элемент в позиции, на которую указывал итератор, был просто удален! И на этом же итераторе в следующем цикле for в вашем коде предпринимается попытка приращения! Вот почему это не удается.
Однако, стереть это вернет итератор, указывающий на новую позицию, которую мы можем использовать; цикл, в котором вы стираете что-то из контейнера STL, должен выглядеть примерно так: Я показываю это с типом, который вы используете, список, но вы могли бы также использовать, например. вектор:
list<int> L;
// ...
list<int>::iterator it=L.begin();
while (it!=L.end())
{
if(eraseCondition)
{
it=L.erase(it);
}
else
{
++it;
}
}
Или, если возможно, еще лучше использовать std::remove_if
:
container.erase(std::remove_if(L.begin(), L.end(), predicate), L.end());
В вашем случае это будет трудно — если не невозможно — использовать, так как predicate
понадобится информация о состоянии (информация о том, является ли индекс нечетным или четным). Поэтому я бы рекомендовал использовать структуру цикла, как указано выше; просто имейте в виду remove_if для общего случая удаления всех элементов, где определенный предикат возвращает true!
В дополнение к тому, что сказал wOOte, вы можете использовать обратный итератор, чтобы обойти проблему.
Технически не в этом случае.
Когда вы используете erase (), вы удаляете узел, на который был указан, так что вы фактически лишаете законной силы итератор, на котором вы были. Поэтому, когда вы увеличиваете его, это неопределенное поведение.
Лучше всего создать второй список, содержащий только итераторы для позиций, которые вы хотите удалить, и вы можете циклически перемещаться по ним и затем вызывать стирание. Вы не будете стирать итераторы из второго списка, так что это сработает.
Что-то вроде этого:
List<IteratorType> deleteList;
//Populate deleteList with every other element from original list.
for (List<IteratorType>::iterator iter = deleteList.begin();
iter !=deleteList.end; ++iter)
{
originalList.erase(*iter);
}
Итератор i
признан недействительным erase
; однако в следующей итерации for
цикл, вы пытаетесь увеличить его — это неверно.
Пытаться
for(i=L.begin() ; i!=L.end() ; )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i=L.erase(i);
} else {
++i;
}
k++;
}
вместо этого — увеличивайте итератор только в том случае, если вы не удаляете его (стирание в основном «продвигает» итератор, потому что он возвращает итератор для элемента, следующего за тем, который вы удалили).
Вы действительно можете использовать это поведение erase
написать свою функцию без необходимости k
:
i = L.begin();
while ( i != L.end() ) {
i = L.erase( i ); // Delete one
if ( i != L.end() ) { // Skip next, if there's an element
++i;
}
}
Таким образом, вы удаляете первый элемент, пропускаете второй, удаляете третий и так далее.