473,405 Members | 2,279 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,405 software developers and data experts.

Is this the wrong way to use std::list?

So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient )
{
m_listClients.push_back( *pClient );
}
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID )
{
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?

Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?

Thanks in advance,
Tom Junior

Jan 4 '08 #1
7 2321
On Jan 4, 2:26 pm, TBass <t...@automateddesign.comwrote:
So I have a class:

class Client
{
unsigned int ClientID;
....

};
Lets assume that the compiler generated copy ctor for Client works for
now.
>
class MyListenSocket
{
...
AddClient( Client *pClient);
It would be interesting to know how you are managing the pointer
above.

public:
void AddClient( const Client& client ); // much better
RemoveClient( unsigned int ID );
private:
std::list<Client m_listClients;

};

To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient )
{
m_listClients.push_back( *pClient );

}

But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID )
void MyListenSocket::RemoveClient( const unsigned id )
{
std::list<Client>::iterator it;
typedef std::list<Client>::iterator LIter;
LIter it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}

}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?
The iterator is not corrupted, it gets invalidated. Your free store is
suffering from something else.
i'ld probably use a std::set instead of a std::list.
>
Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?

Thanks in advance,
Tom Junior
Jan 4 '08 #2
TBass wrote:
So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient )
{
m_listClients.push_back( *pClient );
}
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID )
{
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?

Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?
As others have stated, there are a few problems with this code, or can be.

First, as stated, erase invalidates iterators. So you need to use the
algorithm:

for( it = m_listClients.begin(); it != m_listClients.end(); )
{
if ( it->ClientID() == ID )
{
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

Second, the desturctor for the Client is not being called. Now, if clients
are creating using new, then you'll need to delete the pointer with delete.
This will also free the memory so you don't get a memory leak.

for( it = m_listClients.begin(); it != m_listClients.end(); )
{
if ( it->ClientID() == ID )
{
delete (*it);
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This depends though on the ownership of the Client pointer. Who owns the
pointer? If your m_list_Clients is the only place you are keeping this
pointer, then m_listClients owns the pointer and needs to delete it when it
gets erased.
--
Jim Langston
ta*******@rocketmail.com
Jan 4 '08 #3
TBass <tb*@automateddesign.comwrote in news:f4b94cc5-b061-424f-bba0-
2d**********@i29g2000prf.googlegroups.com:
So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient )
{
m_listClients.push_back( *pClient );
}
Why is this function taking a client by pointer? Why confuse the issue?
have it take the Client by const-reference.
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID )
{
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?
Because you've got a problem somewhere else. Check your Client class to
make sure that it is properly copy constructable and assignable.
Jan 5 '08 #4
On Fri, 04 Jan 2008 12:33:24 -0800, Jim Langston wrote:
TBass wrote:
>So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient ) {
m_listClients.push_back( *pClient );
}
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID ) {
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?

Is this not the way to delete an item from the middle of a list? Should
I not be using ::list for this type of purpose?

As others have stated, there are a few problems with this code, or can
be.

First, as stated, erase invalidates iterators. So you need to use the
algorithm:

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}
This change makes difference only if 'it' is used after the loop and if
value 'past the erased element' is appropriate there. Quite strong
assumption.
>
Second, the desturctor for the Client is not being called. Now, if
clients are creating using new, then you'll need to delete the pointer
with delete. This will also free the memory so you don't get a memory
leak.

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
delete (*it);
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This depends though on the ownership of the Client pointer. Who owns
the pointer? If your m_list_Clients is the only place you are keeping
this pointer, then m_listClients owns the pointer and needs to delete it
when it gets erased.
There are values not objects stored in the list.

--
Tadeusz B. Kopec (tk****@NOSPAMPLEASElife.pl)
Sanity and insanity overlap a fine grey line.
Jan 5 '08 #5
Tadeusz B. Kopec wrote:
On Fri, 04 Jan 2008 12:33:24 -0800, Jim Langston wrote:
>TBass wrote:
>>So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient ) {
m_listClients.push_back( *pClient );
}
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID ) {
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command,
but why would that corrupt the heap?

Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?

As others have stated, there are a few problems with this code, or
can be.

First, as stated, erase invalidates iterators. So you need to use
the algorithm:

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This change makes difference only if 'it' is used after the loop and
if value 'past the erased element' is appropriate there. Quite strong
assumption.
Actually, the for statement is executed until it != m_listClient.end(). If
you don't use this algorithm but ++it in the for statemnet, the iterator
becomes invalidated in the erase staement. ++it is incrementing an
invalidated iterator. What usually happens is that not all elements in the
container are visited, although it's undefined behavior so anything can
happen.

Try running this program and see what output you get.

#include <iostream>
#include <list>

main()
{
std::list<intData;
for ( int i = 0; i < 10; ++i )
Data.push_back(i);

for ( std::list<int>::iterator it = Data.begin(); it != Data.end();
++it )
{
std::cout << *it << "\n";
}
std::cout << "\n";
for ( std::list<int>::iterator it = Data.begin(); it != Data.end();
++it )
{
std::cout << *it << "\n";
if ( *it == 5 )
Data.erase( it );
}
}

For me, Microsoft Visual C++ .net 2003 under XP I get an access violation
reading location...
>Second, the desturctor for the Client is not being called. Now, if
clients are creating using new, then you'll need to delete the
pointer with delete. This will also free the memory so you don't get
a memory leak.

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
delete (*it);
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This depends though on the ownership of the Client pointer. Who owns
the pointer? If your m_list_Clients is the only place you are
keeping this pointer, then m_listClients owns the pointer and needs
to delete it when it gets erased.

There are values not objects stored in the list.
Okay, then they don't need to be deleted. My bad on that.

--
Jim Langston
ta*******@rocketmail.com
Jan 5 '08 #6
On Sat, 05 Jan 2008 14:32:59 -0800, Jim Langston wrote:
Tadeusz B. Kopec wrote:
>On Fri, 04 Jan 2008 12:33:24 -0800, Jim Langston wrote:
>>TBass wrote:
So I have a class:

class Client
{
unsigned int ClientID;
....
};
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
To add clients to the list, AddClient is called:

MyListenSocket::AddClient( Client *pClient ) {
m_listClients.push_back( *pClient );
}
But a client can be erased from anywhere on the list. I wrote this
function:

MyListenSocket::RemoveClient( unsigned int ID ) {
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}

The problem is that this seems to corrupt the heap in my program. I
know that the iterator is corrupted when I use the erase command, but
why would that corrupt the heap?

Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?

As others have stated, there are a few problems with this code, or can
be.

First, as stated, erase invalidates iterators. So you need to use the
algorithm:

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This change makes difference only if 'it' is used after the loop and if
value 'past the erased element' is appropriate there. Quite strong
assumption.

Actually, the for statement is executed until it != m_listClient.end().
If you don't use this algorithm but ++it in the for statemnet, the
iterator becomes invalidated in the erase staement. ++it is
incrementing an invalidated iterator. What usually happens is that not
all elements in the container are visited, although it's undefined
behavior so anything can happen.
After erasing break statement is executed, so no incrementation, just
leaving the loop. Yes, the value of iterator is invalid after that so it
shouldn't be used.
>
Try running this program and see what output you get.

#include <iostream>
#include <list>

main()
{
std::list<intData;
for ( int i = 0; i < 10; ++i )
Data.push_back(i);

for ( std::list<int>::iterator it = Data.begin(); it != Data.end();
++it )
{
std::cout << *it << "\n";
}
std::cout << "\n";
for ( std::list<int>::iterator it = Data.begin(); it != Data.end();
++it )
{
std::cout << *it << "\n";
if ( *it == 5 )
Data.erase( it );
}
}

For me, Microsoft Visual C++ .net 2003 under XP I get an access
violation reading location...
But to be equivalent to original code it should be
if ( *it == 5 )
{
Data.erase( it );
break;
}
and everything is fine (OK, I had to add return type to main).
--
Tadeusz B. Kopec (tk****@NOSPAMPLEASElife.pl)
O'Reilly's Law of the Kitchen:
Cleanliness is next to impossible
Jan 6 '08 #7
Tadeusz B. Kopec wrote:
On Sat, 05 Jan 2008 14:32:59 -0800, Jim Langston wrote:
>Tadeusz B. Kopec wrote:
>>On Fri, 04 Jan 2008 12:33:24 -0800, Jim Langston wrote:

TBass wrote:
So I have a class:
>
class Client
{
unsigned int ClientID;
....
};
>
>
class MyListenSocket
{
...
AddClient( Client *pClient);
RemoveClient( unsigned int ID );
std::list<Client m_listClients;
};
>
>
To add clients to the list, AddClient is called:
>
MyListenSocket::AddClient( Client *pClient ) {
m_listClients.push_back( *pClient );
}
>
>
But a client can be erased from anywhere on the list. I wrote this
function:
>
MyListenSocket::RemoveClient( unsigned int ID ) {
std::list<Client>::iterator it;
for( it = m_listClients.begin();
it != m_listClients.end();
++it )
{
if ( it->ClientID() == ID )
{
m_listClients.erase( it );
break;
}
}
}
>
The problem is that this seems to corrupt the heap in my program.
I know that the iterator is corrupted when I use the erase
command, but why would that corrupt the heap?
>
Is this not the way to delete an item from the middle of a list?
Should I not be using ::list for this type of purpose?

As others have stated, there are a few problems with this code, or
can be.

First, as stated, erase invalidates iterators. So you need to use
the algorithm:

for( it = m_listClients.begin(); it != m_listClients.end(); ) {
if ( it->ClientID() == ID )
{
it = m_listClients.erase( it );
break;
}
else
{
++it;
}
}

This change makes difference only if 'it' is used after the loop
and if value 'past the erased element' is appropriate there. Quite
strong assumption.

Actually, the for statement is executed until it !=
m_listClient.end(). If you don't use this algorithm but ++it in the
for statemnet, the iterator becomes invalidated in the erase
staement. ++it is incrementing an invalidated iterator. What
usually happens is that not all elements in the container are
visited, although it's undefined behavior so anything can happen.

After erasing break statement is executed, so no incrementation, just
leaving the loop. Yes, the value of iterator is invalid after that so
it shouldn't be used.
>>
Try running this program and see what output you get.

#include <iostream>
#include <list>

main()
{
std::list<intData;
for ( int i = 0; i < 10; ++i )
Data.push_back(i);

for ( std::list<int>::iterator it = Data.begin(); it !=
Data.end(); ++it )
{
std::cout << *it << "\n";
}
std::cout << "\n";
for ( std::list<int>::iterator it = Data.begin(); it !=
Data.end(); ++it )
{
std::cout << *it << "\n";
if ( *it == 5 )
Data.erase( it );
}
}

For me, Microsoft Visual C++ .net 2003 under XP I get an access
violation reading location...

But to be equivalent to original code it should be
if ( *it == 5 )
{
Data.erase( it );
break;
}
and everything is fine (OK, I had to add return type to main).
Dag nab it. I missread the entire code. That's what I get for trying to
respond to a post after being up for 24 hours.

--
Jim Langston
ta*******@rocketmail.com
Jan 6 '08 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: JustSomeGuy | last post by:
I need to write an new class derived from the list class. This class stores data in the list to the disk if an object that is added to the list is over 1K in size. What methods of the std stl...
5
by: Eric Lilja | last post by:
Hello, consider this complete program (sorry, it's not minimal but I hope it's readable at least): #include <algorithm> #include <iostream> #include <vector> class Row { public:
44
by: Josh Mcfarlane | last post by:
Just out of curiosity: When would using std::list be more efficient / effective than using other containers such as vector, deque, etc? As far as I'm aware, list doesn't appear to be...
7
by: alex221 | last post by:
In need to implement a tree structure in which every node has arbitrary number of children the following code has come into mind: using std::list; template < class Contents class Tree_node{ ...
8
by: Spoon | last post by:
Hello, Could someone explain why the following code is illegal? (I'm trying to use a list of (C-style) arrays.) #include <list> typedef std::list < int foo_t; int main() { int v = { 12, 34...
0
by: Javier | last post by:
Hi all, I have this code: class A { std::list<Bm_observadores; void function() {
3
by: Ray D. | last post by:
Hey all, I'm trying to pass a list into a function to edit it but when I compile using g++ I continue to get the following error: maintainNeighbors.cpp:104: error: invalid initialization of...
12
by: isliguezze | last post by:
template <class T> class List { public: List(); List(const List&); List(int, const T&); void push_back(const T &); void push_front(const T &); void pop_back();
17
by: Isliguezze | last post by:
Does anybody know how to make a wrapper for that iterator? Here's my wrapper class for std::list: template <class Tclass List { private: std::list<T*lst; public: List() { lst = new...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.