Finding/Searching in std:list

Sep 20, 2013 at 2:32pm
Write your question here.

Hello All,

Problem description:
1) I have a list of ClientInfo objects getting updated using std::list. You can see the registerToMaster() below
2) Similarly i want to unregister and the input i get is clientID as argument. Now i want to search the ClientInfo object whose data member (clientID) matches the client ID provided as argument.

I am stuck in second point. Please let me know if there is any find API or algorithm to do so.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class ClientInfo
{
    public:
        ClientInfo();
        ~ClientInfo();

        U32 msgId;
        U32 cleintID;    /* This is treated as client ID */ 
        U32 timeout;
        U32 gracePeriod;
};


void Master::registerToMaster(ClientInfo& clientInfo)
{
    std::list<ClientInfo*>::iterator itr;

    // Keep inserting the registered clients at end of list 
    itr = ClientList.begin();
    while (itr != ClientList.end())
    {
        itr++;
    }
    ClientList.insert(itr,&clientInfo);
}

void Master::unregisterFromMaster(U32 clientID)
{
     /*search the cleint ID - ???????? */
     /*remove the client from registered list - I am clear about this part*/
}
Sep 20, 2013 at 2:34pm
Why are you using a std::list to hold pointers? You should use std::vector for this, it will make your life easier.
Sep 20, 2013 at 2:40pm
Yeah i can use vectors instead of list, but still query would be same :) Hw i am going to search on basis of clientID ? If u could provide me pointer on query and enlighten my limited knowledge on list and pointer it would be gr8 :)
Sep 20, 2013 at 2:45pm
If you had a filing cabinet with folders in it and papers in those folders that had IDs on them, how would you find the folder with the paper with the ID on it?

Go through each one, open the folder, grab the paper, and look at the ID. Does it match? No? Keep going. Yes? Erase it, and maybe stop looking if you know that the ID exists only once in there.
Last edited on Sep 20, 2013 at 2:45pm
Sep 20, 2013 at 2:47pm
Why are you using a std::list to hold pointers? You should use std::vector for this, it will make your life easier.

How so?
My personal rule of thumb is: if you don't need elements to be allocated contiguously in memory then use std::list instead of std::vector.

As for the OP's code:

First you don't need to iterate at the end just to insert something at the end.
Use list::push_back() instead.
http://www.cplusplus.com/reference/list/list/push_back/

1
2
3
4
void Master::registerToMaster(ClientInfo& clientInfo)
{
    ClientList.push_back(&clientInfo);
}


1
2
3
4
5
6
7
8
9
10
11
12
13
void Master::unregisterFromMaster(U32 clientID)
{
    // at this point I have to ask if std::list is the best choice of a container
    // what if more clients have the same ID?
    // otherwise, if it's guaranteed that a client ID will appear only once in the list...

    for (std::list<ClientInfo *>::iterator i = ClientList.begin(); i != ClientList.end(); ++i)
        if ((*i)->cleintID == clientID) // cleint/client typo???
        {
            ClientList.erase(i);
            break;
        }
}


http://www.cplusplus.com/reference/list/list/erase/

Edit: minor mistake.
Last edited on Sep 20, 2013 at 2:51pm
Sep 20, 2013 at 2:51pm
// what if more clients have the same ID?

Thank you !!
Clients will not have same ID, Actually those are pid's..


Sep 20, 2013 at 2:55pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Master::registerToMaster(ClientInfo& clientInfo)
{
    // Keep inserting the registered clients at end of list
    ClientList.push_back( &clientInfo ) ;
}

void Master::unregisterFromMaster(U32 clientID)
{
    /*search the cleint ID - ???????? */
    /*remove the client from registered list - I am clear about this part*/

    const auto id_equal = [clientID] ( const ClientInfo* p )
    { return p->clientID == clientID ; } ;

    auto iter = std::find_if( ClientList.begin(), ClientList.end(), id_equal ) ;

    if( iter !=  ClientList.end() ) ClientList.erase(iter) ; // erase it
    else { /* not found */ }
}


If clientID is a key (unique, no duplicates), consider using a set with value semantics to hold the ClientInfo objects - std::set<ClientInfo> or std::unordered_set<ClientInfo>
Sep 20, 2013 at 2:55pm
Catfish4 wrote:
How so?
My personal rule of thumb is: if you don't need elements to be allocated contiguously in memory then use std::list instead of std::vector.
That's a bad rule of thumb, there's a difference between "don't need" and "need not". With primitive types especially you should not be using std::list.

Many sources recommend defaulting to std::vector and only using std::list when you need it. For example, Effective C++ says that std::vector should be your default type of container.

I haven't been able to research much on this particular issue though, so if you have some evidence it's better to use std::list over std::vector more often than not (or that using std::vector for holding pointers is not much more efficient than using std::list to hold pointers), please let me know so I can change my ways :)
Sep 20, 2013 at 3:20pm
closed account (3qX21hU5)
It really all depends on your current situation to determine which container you should use.

Personally I think through the problem and try and determine what I need and what I am going to be doing before hand. If I need it to be really efficient with insertions and deletions I will use std::list.

If I need dynamic length and won't really be doing much insertions in the middle of the container I will use std::vector (Though if you know your "high water level" which is basically the maximum number of elements you could possibly have you should use std::array instead because it has less overhead).

If I need a event queue the obvious choice would be using std::queue (IE First in first out).

The point is there isn't really one default container for most situations (Though I will admit most of the time std::vector is used much more often then the others by most people) it should come down to whatever container works best for your situations and your needs (Performance wise and ease of use wise).

Hell sometimes you will need to create your own container for the job since none of the STL containers will work for your particular needs or they won't work well enough.
Last edited on Sep 20, 2013 at 3:20pm
Sep 20, 2013 at 3:23pm
Zereo wrote:
If I need it to be really efficient with insertions and deletions I will use std::list.
You forgot a step. You have to first think why you will be needing insertions and deletions. In many problems they can be avoided entirely even if they at first seem necessary.

I'm interested to know though which containers you had to create yourself because the STL was unsuitable? Exclude any related to hashes or efficiency.
Sep 20, 2013 at 3:35pm
Hmm... Echoes from this thread? http://www.cplusplus.com/forum/general/104953/
Sep 20, 2013 at 3:48pm
closed account (3qX21hU5)
LB wrote:
I'm interested to know though which containers you had to create yourself because the STL was unsuitable? Exclude any related to hashes or efficiency.


In C++ I haven't really had a lot of need to create a custom container mainly because the work wasn't really worth the reward. So really I have only done it once or twice in C++ and I believe both of those times had to do with efficiency and specialization needs.

Though I have created quite a few in C# but I wouldn't really say most of them were "needed" just that they were more specialized for my task at hand and C# provides the features to make creating containers quite simple to do.

Can't really remember specific examples at the moment but will try and dig them up when I get off work.
Last edited on Sep 20, 2013 at 3:48pm
Topic archived. No new replies allowed.