Это выглядит глупо для меня. Но я был в той же ситуации, и я вернулся к отмененным коммитам. Я сделал возврат чисел, поэтому мне приходилось делать возврат для каждого «возврата фиксации».
Теперь моя история коммитов выглядит немного странно.
Это любимый проект, так что все в порядке. Но для реального проекта я бы предпочел перейти к последнему коммиту, прежде чем вернуться, чтобы восстановить весь возвращенный код вместе в одном коммите и более разумном комментарии.
bool IsOdd( int i )
{
return (i&1)!=0;
}
int a[] = {1,2,3,4,5};
vector<int> v( a, a + 5 );
v.erase( remove_if( v.begin(), v.end(), bind1st( equal_to<int>(), 4 ) ), v.end() );
// v contains {1,2,3,5}
v.erase( remove_if( v.begin(), v.end(), IsOdd ), v.end() );
// v contains {2}
Вы можете, если не аннулируете свой итератор после его стирания:
MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
if (*it == matchingValue)
{
myContainer.erase(it++);
}
else
{
++it;
}
}
template <class Container, class Predicate>
void eraseIf( Container& container, Predicate predicate ) {
container.erase( remove_if( container.begin(), container.end(), predicate ), container.end() );
}
// pre-c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
typename std::map<K,V>::iterator iter = container.begin();
while(iter!=container.end()) {
iterator current = iter++;
if(predicate(*current))
container.erase(current);
}
}
// c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
auto iter = container.begin();
while(iter!=container.end()) {
if(predicate(*iter))
iter = container.erase(iter);
else
++iter;
}
}
Пример с std :: vector
#include <vector>
using namespace std;
int main()
{
typedef vector <int> int_vector;
int_vector v(10);
// Fill as: 0,1,2,0,1,2 etc
for (size_t i = 0; i < v.size(); ++i){
v[i] = i % 3;
}
// Remove every element where value == 1
for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){
if (*it == 1){
it = v.erase(it);
} else {
++it;
}
}
}
Я предпочитаю версию с , а
:
typedef std::list<some_class_t> list_t;
void f( void ) {
// Remove items from list
list_t::iterator it = sample_list.begin();
while ( it != sample_list.end() ) {
if ( it->condition == true ) {
it = sample_list.erase( it );
} else ++it;
}
}
С , в то время как
нет опасности увеличить это
вдвое, как это могло бы быть в для
петля.
markh44 - это самый STL-подобный ответ. Обратите внимание, однако, что в общем случае итераторы становятся недействительными при изменении контейнера, но set и map являются исключениями. Там вы можете удалить элементы и по-прежнему использовать итераторы, за исключением случаев, когда вы удаляете тот самый элемент, на который ссылается итератор.
Решение Виктора имеет тот плюс, что можно что-то сделать с элементом перед удалением. (Я не смог сделать этого с remove_if
или remove_copy_if
). Но я предпочитаю использовать std::find_if
, чтобы никогда не увеличивать итератор самостоятельно:
typedef vector<int> int_vector;
int_vector v;
int_vector::iterator itr = v.begin();
for(;;)
{
itr = std::find_if(itr, v.end(), Predicate(4));
if (itr == v.end())
{
break;
}
// do stuff with *itr here
itr = v.erase(itr); // grab a new, valid iterator
}
Где предикат может быть bind1st( equal_to
или что-то вроде этого:
struct Predicate : public unary_function<int, bool>
{
int mExpected;
Predicate(int desired) : mExpected(desired) {}
bool operator() (int input)
{
return ( input == mExpected );
}
};