He said he wanted to use the erase-remove idiom, so here's a possible way, using a function object:
struct Unifier{
set<int> foundElements;
bool operator()(int & a){
if(foundElements.find(a) != foundElements.end()){
return true;
}else{
foundElements.insert(a);
return false;
}
}
};
int main(){
list<int> v;
v.push_back(5);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.push_back(5);
v.push_back(3);
copy (v.begin(), v.end(), ostream_iterator<int>(cout," "));
Unifier u;
v.remove_if(u);
cout << endl << "After:" << endl;
copy (v.begin(), v.end(), ostream_iterator<int>(cout," "));
}
Update: The above code has a subtle bug. According to C++11 [algorithms.general]/10
:
[Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper<T>
(20.8.3), or some equivalent solution. —end note ]
There appears to be no "otherwise specified" for std::list::remove_if
, so this code may fail to remove all duplicates because it may create copies of the predicate at the start, and then use different copies of the predicate for different parts of the list. Example of this actually happening for std::remove_if.
A simple fix for C++11 is to replace v.remove_if(u)
with:
v.remove_if( reference_wrapper<decltype(u)>(u) );
In C++03 I'm not sure if the above quote was present; but if it was then a fix would be to make foundElements
be static, or to refactor Unifier
so that all copies of it reference a single instance of foundElements
.
Link to related question