STL function REMOVE doesn't work

Discussion in 'C++' started by Tony Johansson, May 17, 2005.

  1. Hello!

    I have some problem with STL function remove

    I have two classes called Handle which is a template class and Integer which
    is not a template class. The Integer class is just a wrapper class for a
    primitive int with some methods. I don't show the Integer class because it
    will not add any information to my problem. Main is using some STL function

    Now to my problem.
    If I do this sequence in main first create two Handle object myh1 and myh2.
    Then I use push_front to first push in myh1 and then myh2 into the list
    Then I use the STL function for_each in this way
    for_each(myList1.begin(), myList1.end(), handle_t() );
    The function operator would write 2 and then 1 because I pushed_front the
    Handle myh1 and then myh2

    This function for_each will write out the entire list by calling the
    function operator defined as
    void operator()(Handle& temp) //Funktionsanropsoperator
    { cout << *temp.body << endl; }
    for each Handle in the list. The function operator will write the primitive
    ints because the wrapper class Integer has a type conversion operator that
    convert from the class Integer to an int.

    When I want to remove a Handle from the list I use the STL function remove
    in this way
    remove(myList1.begin(), myList1.end(), myh2);
    Here I remove the Handle named myh2.

    But now to the very strange thing. I would expect that the destructor for
    Handle would be called when I do the remove but it doesn't. If I want to
    write out the list after I have done the remove I use the for_each again in
    this way.
    for_each(myList1.begin(), myList1.end(), handle_t() );
    The function operator would now write out 1 and then 1. It should only have
    written 1 because the 2 should have been removed. The other strange thing is
    that the removed 3 has been changed to 1 in some strange way that I don't
    understand.

    Have you any suggestion ?

    //Tony


    #include "handle.h"
    #include <list>
    #include <algorithm>
    using namespace std;

    typedef Handle<Integer> handle_t;

    main()
    {
    list<handle_t> myList1;
    handle_t myh1( new Integer(1) );
    handle_t myh2( new Integer(2) );

    myList1.push_front(myh1);
    myList1.push_front(myh2);
    for_each(myList1.begin(), myList1.end(), handle_t());
    remove(myList1.begin(), myList1.end(), myh2);
    for_each(myList1.begin(), myList1.end(), handle_t());
    }

    #include "integer.h"
    #include <iostream>
    using namespace std;

    template<class T>
    class Handle
    {
    public:
    Handle()
    {
    body = new T(0);
    ref_count = new int(1);
    }

    Handle(T* body_ptr) //Constructor
    {
    body = body_ptr;
    ref_count = new int(1);
    }

    ~Handle() //Destructor
    {
    (*ref_count)--;
    if (!*ref_count)
    deleteAll();
    }

    bool operator==(const Handle& temp)
    { return *body == *temp.body; }

    Handle(const Handle& h) //Copy constructor
    {
    body = h.body;
    ref_count = h.ref_count;
    (*ref_count)++;
    }

    void operator()(Handle& temp) //Functionoperator
    { cout << * temp.body << endl; }
    private:
    T* body;
    int* ref_count;

    void deleteAll()
    {
    delete body;
    body = NULL;
    delete ref_count;
    ref_count = NULL;
    }
    };
    Tony Johansson, May 17, 2005
    #1
    1. Advertising

  2. Tony Johansson

    Achintya Guest

    Tony Johansson wrote:
    > Hello!
    >
    > I have some problem with STL function remove
    >
    > I have two classes called Handle which is a template class and

    Integer which
    > is not a template class. The Integer class is just a wrapper class

    for a
    > primitive int with some methods. I don't show the Integer class

    because it
    > will not add any information to my problem. Main is using some STL

    function
    >
    > Now to my problem.
    > If I do this sequence in main first create two Handle object myh1 and

    myh2.
    > Then I use push_front to first push in myh1 and then myh2 into the

    list
    > Then I use the STL function for_each in this way
    > for_each(myList1.begin(), myList1.end(), handle_t() );
    > The function operator would write 2 and then 1 because I pushed_front

    the
    > Handle myh1 and then myh2
    >
    > This function for_each will write out the entire list by calling the
    > function operator defined as
    > void operator()(Handle& temp) //Funktionsanropsoperator
    > { cout << *temp.body << endl; }
    > for each Handle in the list. The function operator will write the

    primitive
    > ints because the wrapper class Integer has a type conversion operator

    that
    > convert from the class Integer to an int.
    >
    > When I want to remove a Handle from the list I use the STL function

    remove
    > in this way
    > remove(myList1.begin(), myList1.end(), myh2);
    > Here I remove the Handle named myh2.
    >
    > But now to the very strange thing. I would expect that the destructor

    for
    > Handle would be called when I do the remove but it doesn't. If I want

    to
    > write out the list after I have done the remove I use the for_each

    again in
    > this way.
    > for_each(myList1.begin(), myList1.end(), handle_t() );
    > The function operator would now write out 1 and then 1. It should

    only have
    > written 1 because the 2 should have been removed. The other strange

    thing is
    > that the removed 3 has been changed to 1 in some strange way that I

    don't
    > understand.
    >
    > Have you any suggestion ?
    >
    > //Tony
    >
    >
    > #include "handle.h"
    > #include <list>
    > #include <algorithm>
    > using namespace std;
    >
    > typedef Handle<Integer> handle_t;
    >
    > main()
    > {
    > list<handle_t> myList1;
    > handle_t myh1( new Integer(1) );
    > handle_t myh2( new Integer(2) );
    >
    > myList1.push_front(myh1);
    > myList1.push_front(myh2);
    > for_each(myList1.begin(), myList1.end(), handle_t());
    > remove(myList1.begin(), myList1.end(), myh2);
    > for_each(myList1.begin(), myList1.end(), handle_t());
    > }
    >
    > #include "integer.h"
    > #include <iostream>
    > using namespace std;
    >
    > template<class T>
    > class Handle
    > {
    > public:
    > Handle()
    > {
    > body = new T(0);
    > ref_count = new int(1);
    > }
    >
    > Handle(T* body_ptr) //Constructor
    > {
    > body = body_ptr;
    > ref_count = new int(1);
    > }
    >
    > ~Handle() //Destructor
    > {
    > (*ref_count)--;
    > if (!*ref_count)
    > deleteAll();
    > }
    >
    > bool operator==(const Handle& temp)
    > { return *body == *temp.body; }
    >
    > Handle(const Handle& h) //Copy constructor
    > {
    > body = h.body;
    > ref_count = h.ref_count;
    > (*ref_count)++;
    > }
    >
    > void operator()(Handle& temp) //Functionoperator
    > { cout << * temp.body << endl; }
    > private:
    > T* body;
    > int* ref_count;
    >
    > void deleteAll()
    > {
    > delete body;
    > body = NULL;
    > delete ref_count;
    > ref_count = NULL;
    > }
    > };


    Hi,

    Please post the Integer class details...

    -vs_p...
    Achintya, May 17, 2005
    #2
    1. Advertising

  3. Re: STL function REMOVE doesn't work. Add the Integer class

    "Achintya" <> skrev i meddelandet
    news:...
    >
    > Tony Johansson wrote:
    >> Hello!
    >>
    >> I have some problem with STL function remove
    >>
    >> I have two classes called Handle which is a template class and

    > Integer which
    >> is not a template class. The Integer class is just a wrapper class

    > for a
    >> primitive int with some methods. I don't show the Integer class

    > because it
    >> will not add any information to my problem. Main is using some STL

    > function
    >>
    >> Now to my problem.
    >> If I do this sequence in main first create two Handle object myh1 and

    > myh2.
    >> Then I use push_front to first push in myh1 and then myh2 into the

    > list
    >> Then I use the STL function for_each in this way
    >> for_each(myList1.begin(), myList1.end(), handle_t() );
    >> The function operator would write 2 and then 1 because I pushed_front

    > the
    >> Handle myh1 and then myh2
    >>
    >> This function for_each will write out the entire list by calling the
    >> function operator defined as
    >> void operator()(Handle& temp) //Funktionsanropsoperator
    >> { cout << *temp.body << endl; }
    >> for each Handle in the list. The function operator will write the

    > primitive
    >> ints because the wrapper class Integer has a type conversion operator

    > that
    >> convert from the class Integer to an int.
    >>
    >> When I want to remove a Handle from the list I use the STL function

    > remove
    >> in this way
    >> remove(myList1.begin(), myList1.end(), myh2);
    >> Here I remove the Handle named myh2.
    >>
    >> But now to the very strange thing. I would expect that the destructor

    > for
    >> Handle would be called when I do the remove but it doesn't. If I want

    > to
    >> write out the list after I have done the remove I use the for_each

    > again in
    >> this way.
    >> for_each(myList1.begin(), myList1.end(), handle_t() );
    >> The function operator would now write out 1 and then 1. It should

    > only have
    >> written 1 because the 2 should have been removed. The other strange

    > thing is
    >> that the removed 3 has been changed to 1 in some strange way that I

    > don't
    >> understand.
    >>
    >> Have you any suggestion ?
    >>
    >> //Tony
    >>
    >>
    >> #include "handle.h"
    >> #include <list>
    >> #include <algorithm>
    >> using namespace std;
    >>
    >> typedef Handle<Integer> handle_t;
    >>
    >> main()
    >> {
    >> list<handle_t> myList1;
    >> handle_t myh1( new Integer(1) );
    >> handle_t myh2( new Integer(2) );
    >>
    >> myList1.push_front(myh1);
    >> myList1.push_front(myh2);
    >> for_each(myList1.begin(), myList1.end(), handle_t());
    >> remove(myList1.begin(), myList1.end(), myh2);
    >> for_each(myList1.begin(), myList1.end(), handle_t());
    >> }
    >>
    >> #include "integer.h"
    >> #include <iostream>
    >> using namespace std;
    >>
    >> template<class T>
    >> class Handle
    >> {
    >> public:
    >> Handle()
    >> {
    >> body = new T(0);
    >> ref_count = new int(1);
    >> }
    >>
    >> Handle(T* body_ptr) //Constructor
    >> {
    >> body = body_ptr;
    >> ref_count = new int(1);
    >> }
    >>
    >> ~Handle() //Destructor
    >> {
    >> (*ref_count)--;
    >> if (!*ref_count)
    >> deleteAll();
    >> }
    >>
    >> bool operator==(const Handle& temp)
    >> { return *body == *temp.body; }
    >>
    >> Handle(const Handle& h) //Copy constructor
    >> {
    >> body = h.body;
    >> ref_count = h.ref_count;
    >> (*ref_count)++;
    >> }
    >>
    >> void operator()(Handle& temp) //Functionoperator
    >> { cout << * temp.body << endl; }
    >> private:
    >> T* body;
    >> int* ref_count;
    >>
    >> void deleteAll()
    >> {
    >> delete body;
    >> body = NULL;
    >> delete ref_count;
    >> ref_count = NULL;
    >> }
    >> };

    >
    > Hi,
    >
    > Please post the Integer class details...
    >
    > -vs_p...


    Hello!!

    Here is the Integer class

    #ifndef INTEGER_H
    #define INTEGER_H
    #include <iostream>


    class Integer
    {
    public:
    Integer()
    {}

    Integer(int value): value_(value)
    {
    copy_cnt = new int(0);
    std::cout << "Creating original:"<< value << std::endl;
    };

    Integer(const Integer& src): value_(src.value_), copy_cnt(src.copy_cnt)
    {
    (*copy_cnt) += 1;
    std::cout << "Creating copy:"<< *copy_cnt << " of:" << value_ <<
    std::endl;
    };

    virtual ~Integer()
    {
    if(*copy_cnt == 0)
    {
    std::cout << "Deleting last: "<< value_ << std::endl;
    delete copy_cnt;
    }
    else
    {
    (*copy_cnt) -= 1;
    std::cout << "Deleting: "<< value_ << "\t\t "<< *copy_cnt << " copies
    are left" << std::endl;
    }
    };

    const Integer& operator=(const Integer& src)
    {
    this->value_ = src.value_;
    if(*copy_cnt == 0)
    {
    delete copy_cnt;
    }
    else
    {
    (*copy_cnt) -= 1;
    }
    copy_cnt = src.copy_cnt;
    (*copy_cnt) += 1;
    return *this;
    }


    bool operator==(const Integer& src) const
    { return this->value_ == src.value_; }

    bool operator!=(const Integer& src) const
    { return this->value_ != src.value_; }

    operator int() const
    { return this->value_; }

    void setValue(int value)
    {
    this->value_ = value;
    if(*copy_cnt > 0)
    {
    *copy_cnt -= 1;
    copy_cnt = new int;
    *copy_cnt = 0;
    }
    }

    private:
    int value_;
    int *copy_cnt;
    };
    #endif
    >
    Tony Johansson, May 17, 2005
    #3
  4. Tony Johansson wrote:
    > Hello!
    >


    [snip]

    >
    > When I want to remove a Handle from the list I use the STL function remove
    > in this way
    > remove(myList1.begin(), myList1.end(), myh2);
    > Here I remove the Handle named myh2.
    >
    > But now to the very strange thing. I would expect that the destructor for
    > Handle would be called when I do the remove but it doesn't. If I want to


    Because 'remove' doesn't destory any iterator. If you print the size of
    the list 'myList1', you will see the size is still same i.e. 2. remove
    returns the iterator of 'newLast', where [myList1.begin(), newLast)
    contains no elements equal to myh2.

    If you want to 'actually' remove the myh2 from myList1, you need to call

    myList1.erase(remove(myList1.begin(), myList1.end(), myh2),
    myList1.end());


    > write out the list after I have done the remove I use the for_each again in
    > this way.
    > for_each(myList1.begin(), myList1.end(), handle_t() );
    > The function operator would now write out 1 and then 1. It should only have
    > written 1 because the 2 should have been removed. The other strange thing is
    > that the removed 3 has been changed to 1 in some strange way that I don't
    > understand.


    After remove, dereferencing the iterators within range [newLast,
    myList1.end()) are legal, but the elements they point to are
    unspecified.

    Krishanu

    --
    "Automatically translated code seldom looks nice and is usually not
    meant to be read by humans..."
    --Jens Thoms Toerring
    Krishanu Debnath, May 17, 2005
    #4
  5. Tony Johansson

    Achintya Guest

    Krishanu Debnath wrote:
    > Tony Johansson wrote:
    > > Hello!
    > >

    >
    > [snip]
    >
    > >
    > > When I want to remove a Handle from the list I use the STL function

    remove
    > > in this way
    > > remove(myList1.begin(), myList1.end(), myh2);
    > > Here I remove the Handle named myh2.
    > >
    > > But now to the very strange thing. I would expect that the

    destructor for
    > > Handle would be called when I do the remove but it doesn't. If I

    want to
    >
    > Because 'remove' doesn't destory any iterator. If you print the size

    of
    > the list 'myList1', you will see the size is still same i.e. 2.

    remove
    > returns the iterator of 'newLast', where [myList1.begin(), newLast)
    > contains no elements equal to myh2.
    >
    > If you want to 'actually' remove the myh2 from myList1, you need to

    call
    >
    > myList1.erase(remove(myList1.begin(), myList1.end(), myh2),
    > myList1.end());
    >
    >
    > > write out the list after I have done the remove I use the for_each

    again in
    > > this way.
    > > for_each(myList1.begin(), myList1.end(), handle_t() );
    > > The function operator would now write out 1 and then 1. It should

    only have
    > > written 1 because the 2 should have been removed. The other strange

    thing is
    > > that the removed 3 has been changed to 1 in some strange way that I

    don't
    > > understand.

    >
    > After remove, dereferencing the iterators within range [newLast,
    > myList1.end()) are legal, but the elements they point to are
    > unspecified.
    >
    > Krishanu
    >
    > --
    > "Automatically translated code seldom looks nice and is usually not
    > meant to be read by humans..."
    > --Jens Thoms Toerring


    Hi,

    Yup,...in other words 'remove' simply moves the selected elements to
    the end of the sequence and returns an iterator to the first 'removed'
    element.

    -vs_p...
    Achintya, May 17, 2005
    #5
  6. On Tue, 17 May 2005 07:11:08 GMT, "Tony Johansson"
    <> wrote:

    >When I want to remove a Handle from the list I use the STL function remove
    >in this way
    >remove(myList1.begin(), myList1.end(), myh2);
    >Here I remove the Handle named myh2.
    >
    >But now to the very strange thing. I would expect that the destructor for
    >Handle would be called when I do the remove but it doesn't.


    The name of this function is confusing -- it doesn't remove anything
    it just reorder the collection. You can think about it like the
    partition in reverse.

    Partition moves given elements to the front of the collection, remove
    -- to the back.

    1 2 3 1

    when you apply the remove function with "1" you will get:

    2 3 1 1

    And now you can apply the erase function. Good STL guide is very
    helpful, try Josuttis, it's category-killer.

    have a nice day
    bye


    --
    Maciej "MACiAS" Pilichowski http://bantu.fm.interia.pl/

    M A R G O T --> http://www.margot.cad.pl/
    automatyczny t³umacz (wczesna wersja rozwojowa) angielsko-polski
    Maciej Pilichowski, May 17, 2005
    #6
  7. On 17 May 2005 00:40:18 -0700, "Achintya" <>
    wrote:

    >Please post the Integer class details...


    And you have to quote the whole message just to add those witty words?

    --
    Maciej "MACiAS" Pilichowski http://bantu.fm.interia.pl/

    M A R G O T --> http://www.margot.cad.pl/
    automatyczny t³umacz (wczesna wersja rozwojowa) angielsko-polski
    Maciej Pilichowski, May 17, 2005
    #7
  8. Tony Johansson

    Rapscallion Guest

    Achintya wrote:
    > Yup,...in other words 'remove' simply moves the selected elements to
    > the end of the sequence and returns an iterator to the first

    'removed'
    > element.


    No, 'remove' may also overwrite and duplicate elements (see e.g.
    Stroustrup). It's a good example of a bad interface design.

    R.C.
    Rapscallion, May 17, 2005
    #8
  9. In message <>, Maciej
    Pilichowski <> writes
    >On Tue, 17 May 2005 07:11:08 GMT, "Tony Johansson"
    ><> wrote:
    >
    >>When I want to remove a Handle from the list I use the STL function remove
    >>in this way
    >>remove(myList1.begin(), myList1.end(), myh2);
    >>Here I remove the Handle named myh2.
    >>
    >>But now to the very strange thing. I would expect that the destructor for
    >>Handle would be called when I do the remove but it doesn't.

    >
    >The name of this function is confusing -- it doesn't remove anything
    >it just reorder the collection. You can think about it like the
    >partition in reverse.
    >
    >Partition moves given elements to the front of the collection, remove
    >-- to the back.


    Not quite. After calling partition() you have exactly the same elements,
    in a different order. All elements are preserved.

    After remove(), the back of the sequence contains garbage - a mixture of
    unwanted elements and _copies_ of the wanted ones. There's no guarantee
    that the unwanted elements are preserved.

    >1 2 3 1
    >
    >when you apply the remove function with "1" you will get:
    >
    >2 3 1 1


    I suspect you'll actually get 2 3 3 1

    >
    > And now you can apply the erase function. Good STL guide is very
    >helpful, try Josuttis, it's category-killer.
    >
    >have a nice day
    >bye
    >
    >


    --
    Richard Herring
    Richard Herring, May 17, 2005
    #9
  10. Tony Johansson

    Mark P Guest

    Tony Johansson wrote:
    > Hello!
    >
    > I have some problem with STL function remove
    >


    This is discussed in Meyer's Effective STL and also in footnote [1] of
    http://www.sgi.com/tech/stl/remove.html

    Note in particular the erase-remove idiom which may be what you're
    looking for.

    Mark
    Mark P, May 17, 2005
    #10
  11. On Tue, 17 May 2005 10:07:37 +0100, Richard Herring <junk@[127.0.0.1]>
    wrote:

    >After remove(), the back of the sequence contains garbage - a mixture of
    >unwanted elements and _copies_ of the wanted ones. There's no guarantee
    >that the unwanted elements are preserved.


    Thank you for pointing that out -- I tried too hard to make an
    analogy, sorry ;-)

    Kind regards,

    --
    Maciej "MACiAS" Pilichowski http://bantu.fm.interia.pl/

    M A R G O T --> http://www.margot.cad.pl/
    automatyczny t³umacz (wczesna wersja rozwojowa) angielsko-polski
    Maciej Pilichowski, May 17, 2005
    #11
  12. Tony Johansson

    msalters Guest

    Rapscallion wrote:
    > Achintya wrote:
    > > Yup,...in other words 'remove' simply moves the selected elements

    to
    > > the end of the sequence and returns an iterator to the first

    > 'removed'
    > > element.

    >
    > No, 'remove' may also overwrite and duplicate elements (see e.g.
    > Stroustrup). It's a good example of a bad interface design.


    It's a good example of generic design. The domain on which
    the STL works is ranges, not containers. You simply cannot
    remove elements from a char[20]. However, you can create
    a subrange within the char[20] that has the desired property. By
    definition, you're not interested in the
    remainder, or you'd use remove_copy/copy_if

    HTH,
    Michiel Salters
    msalters, May 19, 2005
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon-Pierre  Jarry
    Replies:
    2
    Views:
    2,348
    Henrik
    Aug 10, 2005
  2. tshad
    Replies:
    6
    Views:
    21,437
    tshad
    Aug 8, 2006
  3. MZ
    Replies:
    7
    Views:
    812
    Ed Mullen
    Mar 17, 2008
  4. Tilman
    Replies:
    0
    Views:
    403
    Tilman
    Mar 19, 2008
  5. rigo
    Replies:
    0
    Views:
    166
Loading...

Share This Page