2010-04-18 16 views
5

Ok questa volta ho deciso di creare un elenco utilizzando l'STL. Devo creare un socket TCP dedicato per ogni client. Quindi ogni volta che ho una connessione, istanzio un socket e aggiungo un puntatore ad esso su una lista.Non è un Iterator in C++ una specie di puntatore?

list<MyTcp*> SocketList; //This is the list of pointers to sockets 
list<MyTcp*>::iterator it; //An iterator to the list of pointers to TCP sockets. 

Mettere un nuovo puntatore ad una presa di corrente è stato facile, ma ora ogni volta che la connessione viene terminata dovrei scollegare la presa ed eliminare il puntatore in modo che non si ottiene un enorme perdita di memoria, giusto? bene .. Ho pensato che stavo facendo bene impostando questo:

it=SocketList.begin(); 
while(it != SocketList.end()){ 
    if((*it)->getClientId() == id){ 
    pSocket = it; // <-------------- compiler complains at this line 
    SocketList.remove(pSocket); 
    pSocket->Disconnect(); 
    delete pSocket; 
    break; 
    } 
} 

Ma il compilatore dice questo:

error: invalid cast from type ‘std::_List_iterator<MyTcp*>’ to type ‘MyTcp*’ 

Qualcuno mi può aiutare qui? Pensavo che stavo facendo le cose per bene, non è un iteratore in un dato momento semplicemente indicando uno degli elementi del set? come posso ripararlo?

+1

L'iteratore _punti_ in un elemento nel contenitore, quindi è necessario dereferenziarlo utilizzando l'operatore *. – jweyrich

+7

È più facile pensare a un puntatore come a una sorta di iteratore ad accesso casuale ... uno che vede tutta la RAM come un grande vettore. –

risposta

18

Prova questa:

pSocket = *it; 

iteratori agiscono un po 'come i puntatori, ma in realtà può essere un puntatore o una classe a tutti gli effetti che si comporta come uno. La cosa importante in questo caso è che quando ne estrai uno, ottieni qualsiasi oggetto che viene memorizzato nel contenitore. Poiché si memorizzano i numeri MyTcp* nell'elenco, quando si dereferenzia l'iteratore si ottiene MyTcp*. pSocket è di tipo MyTcp* quindi l'assegnazione sopra ha esito positivo. Il compito che stai tentando di fare non è dereferenziare l'iteratore: stai tentando di assegnare l'iteratore stesso a pSocket.

È genere come il seguente caso:

void foo() 
{ 
    MyTcp *array[10]; // An array full of MyTcp pointers 
    MyTcp **iterator = NULL; // pointers make good iterators for arrays (but not for std::lists) 
    for (iterator = array; iterator != array + 10; ++iterator) 
    { 
     // This fails to compile (cannot assign MyTcp** to MyTcp*: 
     MyTcp *wrong = iterator;    

     // This succeeds: 
     MyTcp *current = *iterator; // important to dereference the iterator 
    } 
} 
+0

@Eclipse: [su puntatori ed iteratori] "quando ne estrai uno, ottieni ciò che viene memorizzato nel contenitore ..." Non è lo stesso con i puntatori? * C'è NESSUNA differenza tra i puntatori e gli iteratori C++? * – Lazer

+0

@eskay: Puoi pensare ai puntatori come a un tipo di iteratore, in particolare un "Random Access Iterator" sulla memoria grezza. vedere http://www.sgi.com/tech/stl/RandomAccessIterator.html per il requisito di quel tipo di iteratore. In generale, tuttavia, gli iteratori possono essere intere classi che fanno ogni sorta di cose pazze all'interno degli operatori '++' e '*'. Vedi boost.Iterator (http://www.boost.org/doc/libs/1_42_0/libs/iterator/doc/index.html) per un'idea di alcune delle cose che gli iteratori possono davvero fare. – Eclipse

+0

Un esempio tardivo: std :: list stesso è una lista doppiamente collegata. Ogni elemento dell'elenco è memorizzato individualmente/indipendentemente da qualche parte nell'heap, quindi iteratore necessita di una sorta di puntatore al nodo dell'elenco corrente. operator ++ quindi non può eseguire alcun tipo di addizione semplice, invece deve impostare il proprio puntatore del nodo sul valore a cui punta il puntatore "successivo" del nodo. (Oh, modo, così tanti "punti" ...) Quindi, in realtà, non è semplicemente un puntatore, ma un'intera classe avvolta attorno al puntatore reale (il puntatore dovrebbe essere l'unico dato necessario, comunque, quindi la dimensione di iteratore e puntatore dovrebbe essere lo stesso). – Aconcagua

4

Un iteratore potrebbe essere implementata da un puntatore (nel caso del vettore, è). Gli iteratori hanno una semantica dei puntatori: li si sceglie per ottenere il valore.

Ma stai memorizzando i puntatori nell'elenco. Il "MyTcp *" è il tuo valore, quindi per assegnarlo, devi dereferenziare "it".

pSocket = *it; 
+0

Gli iteratori vettoriali non sono sempre puntatori. –

3

Un iteratore non solo puntare a uno degli elementi, e la sintassi per dereferencing è lo stesso, ma è un tipo diverso (con una diversa rappresentazione in memoria), e puntatori su esso fa qualcosa diverso da quello che fa su un puntatore (cioè il risultato di punti aritmetici di iteratore su una posizione di memoria diversa da quella che si otterrebbe se si convertisse l'iteratore in un puntatore e si eseguisse l'aritmetica del puntatore), quindi di solito non si vogliono confondere i due tipi.

Tuttavia, dato il tipo che l'elenco è un elenco di puntatori, e si sta solo dereferenziazione pSocket volta nella chiamata pSocket->Disconnect();, credo che la risposta di Eclipse è ciò che si vuole: pSocket = *it;

6

Un iteratore è una generalizzazione di un puntatore. C'è un buon articolo in Wikipedia sul modello Iterator.

Il motivo per cui gli iteratori vengono utilizzati nell'STL consiste nel rendere gli algoritmi ortogonali ai contenitori. Qualsiasi contenitore può essere utilizzato con (quasi) qualsiasi algoritmo purché tale contenitore supporti iteratori.

Problemi correlati