There are more and more people using STL. STL is indeed a set of beautiful algorithms and data structure libraries, but people who use STL at first often encounter many problems.
Deleting an element from a container is a very common operation, but it is also a common mistake for beginners. The last time baosong found an error occurred when deleting the elements in map and list. vector is a very common container in STL. Compared with containers such as map and list, it is more troublesome to delete elements that meet certain conditions from the vector.
For example, we need to complete the following tasks.
Has the following struct
Class AA
{
Public:
AA (): n (0 ){}
AA (int B): n (B ){}
Int N;
};
There is a vector
Vector <AA> VAA;
A list
List <int> intlist;
Now we need to perform this operation to delete all the elements in intlist of all member variables N in VAA. What should we do? We can have the following options:
1 handwriting cycle
Follow the delete method of list.
Vector <AA >:: iterator ite = VAA. Begin ();
For (; ite! = VAA. End ();)
{
If (find (intlist. Begin (), intlist. End (), ite-> N )! = Intlist. End ())
VAA. Erase (++ ITE );
Else
++ Ite;
}
The erase of the vector is characterized by that the deleted element and the iterator of all subsequent elements are invalid, even if the next iterator is saved, and cannot continue traversing. for this continuous storage sequence, you should replace unnecessary elements with the expected ones, and then delete the elements that do not end with them. like this:
Vector <AA >:: iterator ite = VAA. Begin ();
Vector <AA >:: iterator DEST = ite;
For (; ite! = VAA. End (); ++ ITE)
{
If (find (intlist. Begin (), intlist. End (), ite-> n) = intlist. End ())
{
* DEST ++ = * ite;
}
}
VAA. Erase (DEST, VAA. End ());
2. Use remove_if to write a judgment function as a condition.
Writing a loop like above is troublesome, error-prone, and hard to read. STL provides an algorithm remove_if, you don't need to write a loop yourself. To complete the above loop function, you just don't need
The elements are replaced by the required elements, and the iterator. remove_if prototype at the end is
Template <class forwarditerator, class predicate>
Forwarditerator remove_if (forwarditerator first, forwarditerator last,
Predicate Pred );
PRED is a sub-function used as a judgment condition. A function sub-is a type that can be used according to the function call syntax. It can be a function pointer or a type that has been overloaded with operator. here, PRED requires that the return value be bool. There is a function sub-parameter. The parameter type is the type of elements in the container. If this function is executed for each element, true will be removed.
Therefore, we need to write a function to determine whether an AA-type variable meets the conditions. however, this function obviously requires two parameters, one AA and one list <int>. To avoid copying, we use a pointer to pass the list
Bool inthelist (Aa aa, const list <int> * lint)
{
Return find (lint-> begin (), lint-> end (), AA. N )! = Lint-> end ();
}
To bind the two parameter functions to a function with the previous parameter to a parameter, you can use the bind2nd function in STL. The prototype is as follows:
Template <class adaptablebinaryfunction, class T>
Binder2nd <adaptablebinaryfunction>
Bind2nd (const adaptablebinaryfunction & F, const T & C );
This function will not be executed. The Compiler only relies on it for Type derivation, And it will return an adaptable unary function type. its first parameter is an adaptable binary function, which is a type that redefines operator () and cannot directly pass a function pointer. Therefore, we need the ptr_fun function, ptr_fun's overload prototype for double parameter function pointers is:
Template <class arg1, class arg2, class result>
Pointer_to_binary_function <arg1, arg2, result>
Ptr_fun (result (* X) (arg1, arg2 ));
This function is also used for type derivation and returns an adaptable unary function.
Based on the above functions, you can write them as follows:
VAA. Erase (remove_if (VAA. Begin (), VAA. End (), bind2nd (ptr_fun (inthelist), & intlist), VAA. End ());
Note: It may be a vc6 bug. If inlist is a static member function of the class, the above Code cannot be compiled in vc6, and vc6 cannot deduce the type of the function sub-function, the above code is available in vc8 and GCC. for vc6, We need to explicitly tell the compiler that we pass the function pointer, as shown below:
VAA. Erase (remove_if (VAA. Begin (), VAA. End (), bind2nd (ptr_fun (& inthelist), & intlist), VAA. End ());
We can also make inthelist a member function of AA.
Bool AA: inthelist (const list <int> * lint)
{
Return find (lint-> begin (), lint-> end (), n )! = Lint-> end ();
}
STL provides a set of functions that convert member functions into single-or double-parameter functions. mem_fun1_ref. here we can use the following delete operation to write it:
VAA. erase (remove_if (VAA. begin (), VAA. end (), bind2nd (mem_fun1_ref (& AA: inthelist), & intlist), VAA. end ());
3. Use remove_if to define the sub-type of the function that determines the condition.
The above conversion and binding will surely make people crazy. Using function pointers to pass judgment conditions is also inefficient. we can define a type ourselves.
Class inlistfunctor
{
Public:
Inlistfunctor (const list <int> & lint): m_list (lint)
{}
Bool operator () (aa)
{
Return find (m_list.begin (), m_list.end (), A. N )! = M_list.end ();
}
PRIVATE:
Const list <int> & m_list;
}
In this way, the object can be directly transmitted to remove_if. The const reference of inlistfunctor accepts a list <int> and the list to be compared can be passed in.
VAA. Erase (remove_if (VAA. Begin (), VAA. End (), inlistfunctor (intlist), VAA. End ());
You can create complex comparison conditions using a Defined Function Sub-Statement, which is more convenient and free.
4. Use boost: Lambda to construct an anonymous function.
The above two methods have a common determination, either defining a function or defining a type, which will add unnecessary things to a class, in actual programming, this will make people feel
It's not good. Using boost: Lambda can construct an anonymous function, without causing any pollution to the class namespace. However, this work is a bit complicated for Boost: Lambda and must include the following three
Boost: Lambda header file, open the boost: Lambda namespace.
# I nclude <boost/lambda/Lambda. HPP>
# I nclude <boost/lambda/Bind. HPP>
# I nclude <boost/lambda/algorithm. HPP>
Using namespace boost: Lambda;
The delete operation can be written as follows:
VAA. Erase (remove_if (VAA. Begin (),
VAA. End (),
BIND (LL: Find (), intlist. Begin (), intlist. End (), (& _ 1)-> * & AA: N )! = Intlist. End ()),
VAA. End ());
It looks a bit complicated. For details about boost: Lambda usage, refer to its documentation. I cannot say a word or two. in the above formula, _ 1 is the key of Lambda, which refers to the first parameter of the generated function. here is the AA type element.