Topic: STL bug with example: remove_if() looses function state


Author: Nico Josuttis <nico@bredex.de>
Date: 1996/04/19
Raw View
Some people asked for an example of my remove_if() problem.
Here is the problem with example.

The example uses remove_if() to remove only the first element
with a given value.
A function object (that has no side effects)
is designed to return true only for the first
element having a given value.
But using it as parameter of remove_if(), it is
duplicated and thus does return true twice.
That results in removing not only the first but also the
second element. OOOPS

------------------------- snip -----------
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

class FirstElemWithValue {
  private:
    int  value;
    bool found;
  public:
    FirstElemWithValue (int v) : value(v), found(false) {
    }
    bool operator() (int elem) {
 // return true only for the first found elem
        if (!found && elem == value) {
            found = true;
            return true;
        }
        return false;
    }
};

int main ()
{
    list<int> m;

    m.push_back (1);
    m.push_back (2);
    m.push_back (4);
    m.push_back (3);
    m.push_back (5);
    m.push_back (6);
    m.push_back (2);
    m.push_back (0);
    m.push_back (2);

    copy (m.begin(), m.end(), ostream_iterator<int>(cout," "));
    cout << endl;

    /* remove first element with value 2
     */
    list<int>::iterator pos;
    pos = remove_if (m.begin(), m.end(),
       FirstElemWithValue(2));
    m.erase (pos, m.end());

    copy (m.begin(), m.end(), ostream_iterator<int>(cout," "));
    cout << endl;
}
------------------- snip --------------------------

The output is:
 1 2 4 3 5 6 2 0 2
 1 4 3 5 6 0 2
but should be:
 1 2 4 3 5 6 2 0 2
 1 4 3 5 6 2 0 2

This happens due to the current implementation of
remove_if() which calls find_if() and remove_copy_if():

 > template <class ForwardIterator, class Predicate>
 > ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
 >                           Predicate pred) {
 >   first = find_if(first, last, pred);
 >   ForwardIterator next = first;
 >   return first == last ? first : remove_copy_if(++next, last, first, pred);
 > }

So pred() is called with two different copies of
FirstElemWithValue.

I think it would be better/necessary to disallow such implementations,
what means to disallow that a function object gets copied before
calling operator().  At least it should not be allowed that operator()
is called by different copies of the function object.  Otherwise we
would lose the advantage of function objects in a significant matter.

Am I missing something ?

--
Nico                             address: BREDEX GmbH, Nicolai Josuttis
email:   nico@bredex.de                   Fallersleber-Tor-Wall 23
phone:   +49 531 24330-0                  D-38100 Braunschweig
fax:     +49 531 24330-99                 Germany
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]