Разве ptr_vector итератор не требует приращений? - PullRequest
2 голосов
/ 23 октября 2010
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
using namespace std;

class Derived
{
public:
        int i;
        Derived() {cout<<"Constructed Derived"<<endl;}
        Derived(int ii):i(ii) {cout<<"Constructed Derived"<<i<<endl;}
        ~Derived() {cout<<"* Destructed Derived"<<i<<endl;}
};

int main()
{
   boost::ptr_vector<Derived> pv;
   for(int i=0;i<10;++i) pv.push_back(new Derived(i));

   boost::ptr_vector<Derived>::iterator it;
   for (it=pv.begin(); it<pv.end();/*no iterator increment*/ )
        pv.erase(it);
   cout<<"Done erasing..."<<endl;
}

Обратите внимание, что второй цикл for не увеличивает итератор, но выполняет итерацию и стирает все элементы. Мои вопросы:

  1. Правильна ли моя техника итерации и использования итератора?
  2. Если приращение итератора в цикле for не требуется, то где происходит приращение?
  3. Лучше использовать итератор или будет достаточно обычного целого числа (т. Е. Есть ли дополнительные значения с использованием итераторов)? (Потому что я также могу стереть 5-й элемент, как pv.erase (pv.begin () + 5);)
  4. Есть ли способ напрямую назначить новый объект определенной позиции (скажем, 5-й позиции) ptr_vector? Я ищу что-то вроде pv [5] = new Derived (5) ;. Есть ли способ сделать это?

Ответы [ 2 ]

3 голосов
/ 23 октября 2010

A ptr_vector::iterator увеличивается, как обычный итератор произвольного доступа.В вашем примере вы можете стереть каждый элемент без фактического увеличения, потому что после удаления элемента каждый элемент после его перемещения перемещается в массиве.Поэтому, когда вы стираете 0-й элемент, ваш итератор теперь указывает на элемент, который использовал в качестве 1-го элемента, но теперь является 0-м элементом и т. Д.Другими словами, итератор остается на месте, пока весь вектор смещается влево.

Это не имеет никакого отношения к ptr_vector.Обратите внимание, что такое же поведение будет происходить с простым std::vector.

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

 for (it = pv.begin(); it != pv.end(); )
        it = pv.erase(it);

Что касается других ваших вопросов:

Если вы хотите стереть только определенный элемент, то, конечно, вы должны стереть его напрямую, используя pv.erase(pv.begin() + N).Чтобы назначить новое значение определенному элементу в векторе указателя, просто скажите pv[N] = Derived(whatever).Вам не нужно использовать new при переназначении значения.Вектор указателя вызовет оператор присваивания объекта по индексу, которому вы присваиваете новое значение.

1 голос
/ 23 октября 2010

Является ли мой метод итерации и использование итератора правильным?

Нет, удаление из контейнера обычно делает итератор недействительным для стертого элемента.Если это работает, это всего лишь побочный эффект от деталей реализации.

Правильный способ - использовать возвращаемое значение метода стирания:

 it = pv.erase(it);

Однако для опустошенияконтейнер, вы можете использовать функцию очистки члена.

Если приращение итератора в цикле for не требуется, то где происходит приращение?

Это не 'Это произойдет, потому что вы всегда будете стирать первый элемент в контейнере (случайно это может не сработать с другими контейнерами).

Лучше использовать итератор или будет обычное целое числодостаточно (то есть: есть ли добавление стоимости с использованием итераторов)?(потому что я также могу стереть пятый элемент, например pv.erase(pv.begin()+5);)

В контейнере с произвольным доступом вы можете сделать это, в противном случае нет (например, список).

Есть ли способ напрямую назначить новый объект определенной позиции (скажем, 5-й позиции) ptr_vector?Я ищу что-то вроде pv[5]=new Derived(5);.Любой способ сделать это?

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

pv.replace(5, new Derived(5));

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

Или:

pv[5] = Derived(5);

, но это просто изменит сохраненный объект, а не изменит указатель.

...