如何根据条件从矢量中删除元素?

时间:2014-08-28 08:58:46

标签: c++

我有一个向量,我用于观察者模式来注册名称和指针:注册列表。 我想从向量对中取消注册观察者。 我不知道该怎么办,我试过这个,但根本没有编译。

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 个答案:

答案 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就不会工作,你必须亲自动手编写循环代码。