2014-08-28 154 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; 
      } 
     } 
    } 

如何根据pair元素中的某个值从矢量中移除元素?

+2

任何不使用std :: map的原因? – Zoomulator 2014-08-28 09:00:52

+0

可能的重复:http://stackoverflow.com/questions/39912/how-do-i-remove-an-item-from-a-stl-vector-with-a-certain-value – Ilya 2014-08-28 09:03:55

+0

你打算告诉我们吗编译器错误是什么?什么是“观察者”? – juanchopanza 2014-08-28 09:07:58

回答

3

您应该使用vector::erase()来代替。

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

它工作正常。谢谢您的帮助。 – abter 2014-08-28 09:12:18

+0

这很危险,因为它会使迭代器无效! – Zoomulator 2014-08-28 10:48:41

+0

只要擦除一旦发生环路断裂,这根本就不成问题。 – timrau 2014-08-28 11:14:48

0

您当前的代码存在一些问题。

std :: remove会发现和移动元素等于给定的值到容器的末尾。然后它返回指向矢量中未去除范围的末尾的迭代器。要完全删除它们,需要使用vector.erase和从remove算法返回的迭代器。

擦除-remove惯用法:

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)的最坏情况,其中基本操作是pair元素的副本。如果需要比O(N)更好的性能,你必须用std :: map <字符串,Observer *>或者boost :: bimap来安排你的观察者,这可以让你使用两个值作为键。

remove_if和copy_remove_if之间的区别是保留顺序。 remove_if可以交换元素并将它们放置在其他位置以便将已移除的元素移到结束范围。 copy_remove_if将不会将其复制到新容器中,因此顺序将被保留。

如果你不使用C++ 11,lambda不会工作,你将不得不自己手动编写循环。