Monday, January 16, 2012

STL List remove()

STL Lists are a kind of sequence container and among the most widely used. 
Here i will discuss just about one function remove.
void remove(const T& value)
SGI says: Removes all elements that compare equal to val. The relative order of elements that are not removed is unchanged, and iterators to elements that are not removed remain valid. This function is linear time: it performs exactly size() comparisons for equality.
    So if we have a list of integer say:           lst: 1,2, 4,6 4,5,9
    and we say                                            lst.remove(4);
    then remaining list be                              lst: 1,2,6,5,9
Internally remove function iterate complete list, compare and remove all elements equal to 4.  With intrinsic /in-built data-type simple comparison provided by c++ works fine.
Now what if we have a list of  class object. 
As in following example:

#include "iostream"
#include "list"
using namespace std;
class lstTest {
public:
    lstTest(int d=0):i(d) {}
    int getData() const {return i;} 
private:
    int i;
};
int main() {
    list lstObj;
    list::iterator itr;
    lstTest t(10);
    lstObj.push_back(lstTest(11));
    lstObj.push_back(lstTest(2));
    lstObj.push_back(t);
    lstObj.push_back(lstTest(11));
    for(itr=lstObj.begin(); itr!= lstObj.end();itr++)
        cout << (*itr).getData() << endl;
    lstObj.remove(t);
    for(itr=lstObj.begin(); itr!= lstObj.end();itr++)
        cout << (*itr).getData() << endl;
    return 0;
}
on compilation we get following error:

/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/list.tcc: In member function ‘void std::list<_Tp, _Alloc>::remove(const value_type&) [with _Tp = lstTest, _Alloc = std::allocator, std::list<_Tp, _Alloc>::value_type = lstTest]’:
listTest.cpp:25:20:   instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/list.tcc:249:4: error: no match for ‘operator==’ in ‘__first.std::_List_iterator<_Tp>::operator* [with _Tp = lstTest, std::_List_iterator<_Tp>::reference = lstTest&]() == __value’
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/list.tcc:249:4: note: candidates are:
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/postypes.h:218:5: note: template bool std::operator==(const std::fpos<_StateT>&, const std::fpos<_StateT>&)
...
...

so why this Kolavery..... Kolavery ji...

As i discussed earlier remove perform comparisons for equality so for UDT we need to help remove(...) by providing customize "==" operator for class in question. 
For this we need to implement bool operator ==(...) function for class.
So we add following function to  above class:

class lstTest {
public:
    lstTest(int d=0):i(d) {}
    int getData() const {return i;}
    friend bool operator==(const lstTest& o1, const lstTest& o2);
private:
    int i;
};
bool operator==(const lstTest& o1, const lstTest& o2) {
        return o1.i== o2.i;
}

After this "==" overloading above code will works fine.

Now what if you want some thing like this with same class:
    lstObj.remove(11); // removing all object with value of i  = 11
For this we again need to implement another "==" operator for class as follow:
function declaration in class:
friend bool operator==(const lstTest& o1, const int& i);
function definition:
bool operator==(const lstTest& o1, const int& i) { return o1.i== i;}







1 comment:

  1. I think it would be a problem with all reference types in general. But since in-built reference types would already have equality operator overridden, they would not face this issue.

    This article definitely makes me think over how .NET got its IComparable interface. From OOPs design perspective that is how I would think. If I had many UDTs defined to be used in collections, I would like to define an interface that enforces implementation of equality operator overload.

    Great food for thought. Keep it up. Awaiting more.

    ReplyDelete