STL function REMOVE doesn't work

T

Tony Johansson

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;
}
};
 
A

Achintya

Tony said:
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...
 
T

Tony Johansson

Achintya said:
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
 
K

Krishanu Debnath

Tony said:
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
 
A

Achintya

Krishanu said:
Tony said:
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

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...
 
M

Maciej Pilichowski

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
 
R

Rapscallion

Achintya said:
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.
 
R

Richard Herring

Maciej said:
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
 
M

Maciej Pilichowski

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,
 
M

msalters

Rapscallion said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top