2014-08-28 3 views
-4

У меня есть вектор, который я использую для шаблона наблюдателя для регистрации имени и указателя: регистрационный список. Я хочу отменить регистрацию из пары векторов. Я не уверен, как это сделать, я пробовал это, но не компилирую вообще.Как удалить элемент из вектора на основе условия?

vector < pair<string , Observer* > > destination; 

void subject::unregisterObservers(LogObserver* obsIfP) 
    { 
     vector <pair<string, LogObserverIf*> > ::iterator it; 
     for(it = observers.begin(); it != observers.end(); it++) 
     { 
      if((*it).second == obsIfP) 
      { 
       remove(observers.begin(), observers.end(), (*it).first); 
       break; 
      } 
     } 
    } 

Как удалить элементы из вектора на основе одного из значений внутри элемента пары?

+2

Любая причина не в использовании std :: map? – Zoomulator

+0

Возможный дубликат: http://stackoverflow.com/questions/39912/how-do-imove-an-item-from-a-stl-vector-with-a-certain-value – Ilya

+0

Вы собираетесь рассказать нам что такое ошибка компилятора? А что такое 'наблюдатели'? – juanchopanza

ответ

3

Вместо этого вы должны использовать vector::erase().

for(it = observers.begin(); it != observers.end(); it++) 
    { 
     if(it->second == obsIfP) 
     { 
      observers.erase(it); 
      break; 
     } 
    } 
+0

все нормально работает. Спасибо за помощь. – abter

+0

Это опасно, поскольку это приведет к недействительности итераторов! – Zoomulator

+0

Пока цикл прерывается после стирания, это не проблема. – timrau

0

Существует несколько проблем с вашим текущим кодом.

std :: remove найдет и переместить элементов, равных данному значению, в конец контейнера. Затем он возвращает итератор, указывающий на конец неиспользуемого диапазона в векторе. Для их полного удаления потребуется vector.erase с итератором, возвращаемым из алгоритма удаления.

стираньте удаляемую идиома:

v.erase(remove(begin(v), end(v), value), end(v)) 

Обратите внимание, что ваш код дает строку как значение и не будет компилироваться, так как элементы вектора являются парой < строки, наблюдатель *> и алгоритм может Сравним между ними.

Стирание при повторении в том же диапазоне опасно, поскольку вы можете аннулировать итераторы первого цикла.

Использование алгоритмов с предикатами:

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

typedef pair<string, Observer*> RegPair; 
vector<RegPair> new_observers; 
new_observers.reserve(observers.size()); // To avoid resizing during copy. 

remove_copy_if(begin(observers), end(obervers), std::back_inserter(new_observers), 
    [obsIfP](const RegPair& p) -> bool 
     { return p.second == obsIfP; }); 

observers = std::move(new_observers); 

// --- OR THIS 

observers.erase(remove_if(begin(observers), end(observers), 
     [obsIfP](const RegPair& p) -> bool 
      { return p.second == obsIfP; }), 
     end(observers)); 

Удаление элемента в середине вектора заставят все следующие элементы должны быть перемещен обратно один индекс, который, по существу, просто копия в любом случае. Если более одного элемента имеет указатель наблюдателя, ваш исходный код должен будет перемещать эти элементы более одного раза, тогда как это предложение всегда имеет худший случай O (N), где элементарная операция является копией элемента пары. Если требуется более высокая производительность, чем O (N), вам придется упорядочить своих наблюдателей со строкой std :: map <, Observer *> или, возможно, boost :: bimap, которая позволяет использовать оба значения пары в качестве ключей.

Разница между remove_if и copy_remove_if будет сохранением порядка. remove_if может менять элементы и размещать их в другом месте, чтобы получить удаленный элемент в конечный диапазон. Copy_remove_if просто не копирует его в новый контейнер, поэтому порядок сохраняется.

Если вы не используете C++ 11, лямбда не будет работать, и вам придется вручную обработать цикл.

Смежные вопросы