Удаление элемента из вектора при повторении?
У меня есть вектор, содержащий элементы, которые являются активными или неактивными. Я хочу, чтобы размер этого вектора оставался небольшим для проблем с производительностью, поэтому я хочу, чтобы элементы, отмеченные как неактивные, были удалены из вектора. Я попытался сделать это, итерации, но я получаю ошибку "итераторы векторов несовместимы".
vector<Orb>::iterator i = orbsList.begin();
while(i != orbsList.end()) {
bool isActive = (*i).active;
if(!isActive) {
orbsList.erase(i++);
}
else {
// do something with *i
++i;
}
}
Ответы
Ответ 1
Наиболее читаемым способом, который я делал в прошлом, является использование std::vector::erase
в сочетании с std::remove_if
. В приведенном ниже примере я использую эту комбинацию для удаления любого числа, меньшего чем 10, из вектора.
(Для не-С++ 0x вы можете просто заменить lambda ниже своим собственным предикатом:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
Ответ 2
Я согласен с ответом wilx. Вот реализация:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
Ответ 3
Вы можете это сделать, но вам придется немного перетасовать ваш while()
, я думаю. Функция erase()
возвращает итератор в следующий элемент после стираемого: iterator erase(iterator position);
. Цитата из стандарта от 23.1.1/7:
Итератор возвращается из a.erase(q) немедленно указывает на элемент после q до того, как элемент будет стерта. Если такой элемент не существует, Возвращается a.end().
Хотя, возможно, вы должны использовать Erase-remove idiom.
Ответ 4
Если кому-то нужна работа над индексами
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}
Ответ 5
Возможно, вы захотите использовать std::list
вместо std::vector
для своей структуры данных. Он более безопасен (менее подвержен ошибкам) для использования при объединении стирания с итерацией.
Ответ 6
Удаление элементов из середины вектора приведет к аннулированию всех итераторов к этому вектору, поэтому вы не можете этого сделать ( update: не прибегая к предложению Уилкса).
Кроме того, если вы беспокоитесь о производительности, стирание предметов из середины вектора - это плохая идея. Возможно, вы хотите использовать std::list
?
Ответ 7
Как они сказали, векторные итераторы становятся недействительными на vector::erase()
независимо от того, какую форму увеличения итератора вы используете. Вместо этого используйте целочисленный индекс.
Ответ 8
erase
возвращает указатель на следующее значение итератора (аналогично Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}