Как использовать векторные итераторы при использовании vector <> :: push_back ()

0

Для простоты я буду придерживаться vector<int> но я думаю, что это относится к любому vector<T> объекту vector<T>.

Если я использую vector<int>::iterator для отслеживания некоторой позиции в векторе int, а затем использую vector<int>::push_back(), итератор становится бесполезным. Смысл, я не могу принять его адрес & или разыменовать его. Прямая причина имела смысл после того, как я напечатал адрес некоторых объектов в следующем смысле:

vector<int> my_vec(1); //my_vec[0] = 0

vector<int>::iterator it = my_vec.begin(); //it -> my_vec[0], *it = my_vec[0] = 0

cout << "&my_vec = " << &my_vec << "\n";
cout << "&my_vec[0] = " << &my_vec[0] << "\n";
cout << "&it = " << &it << "\n"; //prints address, all good
cout << "*it = " << *it << "\n"; //prints 0, all good

cout << "\n\n" << pushing back..." << "\n\n";
my_vec.push_back(1);

cout << "&my_vec = " << &my_vec << "\n"; //same as before push_back()!
cout << "&my_vec[0] = " << &my_vec[0] << "\n"; //different from before push_back()!!
cout << "&it = " << &it << "\n"; //same as before push_back()
//cannot do &it or *it

Поэтому очевидно, что адрес it не меняется, но push_back() переместилась вещи вокруг в памяти, и теперь адрес различных "элементы" my_vec изменяется. Тот факт, что my_vec [i] имеет новый адрес, имеет смысл для меня, но затем у меня есть следующие вопросы:

1) Почему не меняется адрес my_vec? Похоже, что если push_back() вызывает изменение адресов my_vec[i], он также должен изменить адрес всего объекта. Для массива my_array является указателем на my_array[0] поэтому я могу представить операцию, изменяющую адреса каждого my_array[i] и обновление указателя, чтобы указать на новый адрес my_array[0] но адрес указателя my_array так как объект сам по себе не изменится. Но my_vec не является указателем в каком-либо смысле на my_vec[0] поэтому я смущен, почему адреса my_vec[i] будут меняться, но не объект my_vec.

2) Почему любая операция, внутренняя по отношению к vector<int> которая меняет адрес my_vec[i] (например, push_back()), также неправильно "обновляет" любые итераторы? Это кажется хорошей идеей? Нет?

3) Учитывая, что №2 - это то, что есть, и мои итераторы становятся бесполезными, когда я вызываю push_back(), каков правильный способ справиться с этим? Должен ли я не использовать итераторы, если мне нужно использовать push_back()? Если кто-то собирается жаловаться на то, что мой вариант использования для использования итераторов и push_back(), я исключил его для краткости, но он в основном реализовал стек с помощью vector<int> и я использовал итератор для отслеживания верхнего из стека. Поскольку я не хотел, чтобы фиксированный размер запускался, я попытался использовать push_back() чтобы увеличить стек, когда мой итератор ударил my_vec.end(). Но я думаю, что это правильный вопрос в целом.

Большое спасибо за вашу помощь!

  • 0
    Вы действительно должны задавать только один четкий вопрос за один раз.
  • 0
    @Blastfurnace, я удалил # 4 за ваш комментарий, но ваша ссылка не отвечает # 2, что мне действительно интересно.
Показать ещё 3 комментария
Теги:
iterator
vector
push-back

2 ответа

6
Лучший ответ

Почему не меняется адрес my_vec?

Поскольку сам векторный объект по-прежнему остается одним и тем же объектом по тому же адресу. Перераспределение изменяет адрес динамического массива, которым он управляет, а не векторный объект, управляющий массивом.

Почему любая операция, внутренняя по отношению к vector<int> которая изменяет адрес my_vec[i] (например, push_back()), также неправильно "обновляет" любые итераторы? Это кажется хорошей идеей? Нет?

Это будет иметь (возможно, большую) стоимость исполнения. Любой вектор должен будет отслеживать все итераторы (требующие динамического хранения, распределения памяти при каждом создании итератора и обновления всех векторов при изменении вектора), или каждый итератор должен будет ссылаться на контейнер, проверять на каждый доступ, и не может быть реализована как простой указатель. C++, как правило, позволяет избежать затрат времени исполнения, особенно в таких случаях, когда они почти всегда не нужны.

Каков правильный способ справиться с этим?

Существуют различные варианты. Вы можете сохранить индекс, а не итератор. Вы можете использовать контейнер, такой как std::list со стабильными итераторами (хотя это может быть и менее эффективным). Если вы можете поместить верхнюю границу размера массива, вы можете зарезервировать эту сумму, чтобы перераспределение не требовалось. Вы можете написать свой собственный контейнер (или адаптер), который автоматически обновляет итераторы. Для вашего стека, если это действительно стек, вам не нужно отслеживать ничего, кроме конца вектора, поэтому нет необходимости хранить итератор вообще. Или вы можете использовать std::stack а не изобретать его повторно.

Существуют ли другие функции vector<T> (помимо очевидных), которые оказывают влияние на итераторы?

Итераторы недействительны путем перераспределения, когда любая операция приводит к тому, что вектор будет расти за пределы его текущей емкости. Вы можете управлять емкостью с помощью функции reserve.

Кроме того, стирание элементов приведет к аннулированию любого итератора, ссылающегося на стертые элементы или элементы позже в последовательности.

  • 0
    Спасибо за вашу помощь. Также я реализовывал стек как упражнение, а не изобретать велосипед. Еще раз спасибо!
1

Почему не меняется адрес my_vec?

Перераспределение памяти в std::vector происходит со своим внутренним буфером, который содержит свои элементы, а не сам объект (т. std::vector Не сам std::vector). Рассмотрим следующий пример игрушки:

template<typename T>
class vector {
  T *buffer;
  ...
public:
  ...
};

Если я определяю vector объект (например, vector<int> v), объект v имеет адрес. Когда перераспределение происходит из-за вставки или стирания, это не адрес v который изменяется, а скорее значение его buffer переменной-члена (т. buffer указывает на новое местоположение адреса).

Почему любая операция, внутренняя по отношению к вектору, которая изменяет адрес my_vec [i] (например, push_back()), также не "обновляет" любые итераторы должным образом?

Проблема аннулирования итератора хорошо известна, и вы должны принять ваши меры предосторожности, когда вам приходится иметь дело с такими ситуациями.

Существуют ли какие-либо другие функции-члены вектора (помимо очевидных), которые влияют на итераторы? Это зависит от T?

Да есть (например, std::vector::insert, std::vector::erase). Нет, это не зависит от T (т.е. Типа элемента std::vector).

  • 0
    «адрес его buffer члена» также не изменяется. Адрес, сохраненный в buffer является тем, который изменяется.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню