我有一个向量,我用于观察者模式来注册名称和指针:注册列表。 我想从向量对中取消注册观察者。 我不知道该怎么办,我试过这个,但根本没有编译。
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;
}
}
}
如何根据配对元素中的一个值从矢量中删除元素?
答案 0 :(得分:3)
您应该使用vector::erase()
代替。
for(it = observers.begin(); it != observers.end(); it++)
{
if(it->second == obsIfP)
{
observers.erase(it);
break;
}
}
答案 1 :(得分:0)
您当前的代码存在一些问题。
std :: remove将查找并将移动元素等于给定值到容器的末尾。然后它返回指向向量中未移除范围的末尾的迭代器。要将它们完全删除,需要使用remove.erase和remove算法返回的迭代器。
删除删除习语:
v.erase( remove( begin(v), end(v), value ), end(v) )
注意,您的代码将字符串作为值并且不会编译,因为向量中的元素是对&lt; string,Observer *&gt;并且算法无法在两者之间进行比较。
在相同范围内迭代时擦除是危险的,因为您可能会使第一个循环的迭代器无效。
使用带谓词的算法:
根据矢量的大小,生成新矢量可能更简单(甚至更快)。
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&lt;来安排观察者。 string,Observer *&gt;或者也许是boost :: bimap,它允许你使用两个对值作为键。
remove_if和copy_remove_if之间的区别在于保留顺序。 remove_if可以交换元素并将它们放在别处,以便将删除的元素移到end-range。 如果你没有使用c ++ 11,那么lambda就不会工作,你必须亲自动手编写循环代码。