2015-03-29 4 views
0
  1. Я хочу обработать каждый узел в контейнере vector<int>.STL Как сохранить итератор после удаления()

  2. Пусть vector<int> содержит 0, 1, 2, и 3, и итератор указывает на 2.

  3. Я хочу стереть 2 без потери информации о позиции итератора, так как я хочу, чтобы обрабатывать «3 "после стирания 2.

  4. Вот что я сделал, но результат не показывает, что я намеревался.

  5. Вот мои вопросы:

Q1) Когда vector<int>::iterator oldIter = iter; выполняется, ли oldIter создать новый объект итератора?

Q2) Почему значение итератора остается неизменным после его увеличения?

Q3) Что такое хороший способ стереть узел без потери местоположения итератора?

Q4) Наконец, тривиальный вопрос. Я пробовал cout << iter;, но он не работает. Почему это?

Вот код:

#include <iostream> 
#include <vector> 
using namespace std; 

int main(){ 

vector<int> vContainer; 
vector<int>::iterator iter; 

vContainer.push_back(0); 
vContainer.push_back(1); 
vContainer.push_back(2); 
vContainer.push_back(3); 

for(int i = 0; i < vContainer.size(); i++){ 
    cout << vContainer[i] << endl; 
} 

printf("iter: %x\n", iter); 
iter = vContainer.begin(); 


// Move the itertor to the 2. 
while(*iter != 2){ 
    iter++; 
} 

printf("iter: %x\n", iter); 

vector<int>::iterator oldIter = iter; 
printf("\nBefore erase(oldIter)\n"); 
printf("oldIter: %x\n", oldIter); 
printf("iter: %x\n", iter); 

iter++; 

printf("\nAfter incrementing iter\n"); 
printf("oldIter: %x\n", oldIter); 
printf("iter: %x\n", iter); 

vContainer.erase(oldIter); 

printf("\nAfter erase(oldIter)\n"); 
printf("oldIter: %x\n", oldIter); 
printf("iter: %x\n", iter); 

for(int i = 0; i < vContainer.size(); i++){ 
    cout << vContainer[i] << endl; 
} 

} 

ответ

1

Когда vector<int>::iterator oldIter = iter; выполняется, создать ли oldIter новый объект итератора?

Да.

Почему значение итератора остается неизменным после приращения ?

Это не так. Что заставило вас сделать вывод, что это так? Ваши заявления printf? Они недействительны. printf не знает, как обращаться с векторными итераторами. Ваши обращения к нему - это неопределенное поведение.

Что такое хороший способ стереть узел без потери местоположения итератора ?

Захватить возвращаемое значение вызова erase.

iter = vContainer.erase(iter); 

Наконец, тривиальный вопрос. Я пробовал cout < < iter; но не работа. Почему это?

Поскольку нет operator<< перегрузки, которая принимает std::ostream слева, и вектор итератора справа.И в отличие от printf, std::ostream::operator<< является типичным, поэтому вы получите ошибку времени компиляции, а не неопределенное поведение времени выполнения.

+0

Благодарим вас за повтор. Что касается вопроса (3), где указывает возвращаемое значение? Раньше он указывал на «2», но теперь он ушел. –

+1

@PeterHwang: Он укажет на элемент, который перемещается в стертое положение. 3 в вашем случае. Если вы удалите последний элемент, он вернет итератор, который будет возвращен вызовом 'end()'. –

+0

Если я это правильно понимаю, удалите узел, который указан итератором, и переместите все остальные узлы на единицу. Верный? –

2

В идеале, не удалять узлы индивидуально. Вместо этого используйте std::remove_if() в сочетании с std::vector<...>::erase(): Это превращает потенциально квадратичный алгоритм в линейный. То есть, вы бы использовать что-то вроде этого

vContainer.erase(std::remove_if(vContainer.begin(), 
           vContainer.end(), 
           [](int value){ return someCondition(value); }), 
           vContainer.end()); 

В противном случае, самый простой подход, вероятно, просто восстановить расположение со смещением:

int offset(std::distance(vContainer.begin(), it)); 
vContainer.erase(it); 
it = vContainer.begin() + offset; 

С erase(it) будет переместить все объекты по месту it это довольно дорого. Имея такой алгоритм, как std::remove_if(), суммируйте изменения и перемещайте каждый элемент не чаще одного раза, а не потенциально один раз за erase() намного эффективнее.

адресация ваши конкретные вопросы:

  1. std::vector<int>::iterator oldIter = iter явно создает копию iter. Обратите внимание, однако, что все итераторы ссылаются на объект, на который ссылается it, или после этого объекты недействительны при использовании erase(it).
  2. При наращивании итератора он не остается в том же месте. Если вы считаете, что это возможно, вы, вероятно, неправильно определили местоположение итератора. Наилучшим подходом для определения местоположения итератора для итератора с произвольным доступом является получение смещения от начала последовательности, например, с использованием std::distance(v.begin(), it) (при условии, что it является итератором в диапазоне от v.begin() до v.end()).
  3. Просто держите смещение с самого начала и восстановите его.
  4. Итераторы не могут быть напечатаны. Их ценность не имеет никакого смысла. Тот факт, что вы получили что-то напечатанное с использованием printf(), ничего не значит, потому что тип %x может использоваться только для целочисленных значений и использовать его с другим типом в определенном месте - это неопределенное поведение. См. Выше, как получить разумное указание на расположение итератора. Обратите внимание, что результат std::distance(v.begin(), it) - это некий интегральный тип: вы лучше всего распечатываете его с помощью IOStreams, которые автоматически определяют тип, а не гадают его тип для спецификатора формата printf().
Смежные вопросы