PDA

Visualizza la versione completa : [C++] Aiuto con i templates


Epiphone
13-07-2011, 20:08
Ciao a tutti,
oggi ho cominciato ad usare i templates del c++, in particolare set. Quello che voglio fare una lista di indirizzi ip, e ogni volta che ne ho uno nuovo vedere se esiste o no, in caso non esistesse devo aggiungerlo.
Ora, riduco tutto il codice alla parte che mi interessa:


#include <set>
#include <iostream>
#include <iterator>

using namespace std;

typedef char FLOWID[8]

typedef set <FLOWID> IDF;

FLOWID fid;

int main()
{
fid = indirizzi_ip;

IDF idflow;

if(idflow.insert(fid) == idflow.end(fid))
printf("L'indirizzo è nuovo ed è stato inserito nella lista.\n");
else
printf("L'indirizzo è già presente nella lista.\n");

exit(0)
}


Mi da diversi errori, ma sono sicuro che c'è qualcosa nelle dichiarazioni che sbaglio. Sapete darmi delle linee guida? Ho visto vari siti e vari esempi, e questo è il codice che ho tirato fuori.
Grazie.

shodan
13-07-2011, 20:16
Il tuo problema dipende da quanto riportato qui:
http://www.eptacom.net/pubblicazioni/pub_it/nl_10.html
sotto la voce Vincolare il tipo di stringa (più o meno a metà pagina appena sopra il codice).

Per risolvere:


#include <set>
#include <iostream>
#include <string>
#include <iterator>
using namespace std;

typedef set < string > IDF;

FLOWID fid;

int main()
{
fid = indirizzi_ip;

IDF idflow;

if(idflow.insert(fid) == idflow.end(fid))
printf("L'indirizzo è nuovo ed è stato inserito nella lista.\n");
else
printf("L'indirizzo è già presente nella lista.\n");

exit(0)
}

In ogni caso tieni presente (se non lo sai già) che il set ammette solo elementi univoci, pertanto l'if è puramente informativo

Epiphone
13-07-2011, 21:23
Grazie shodan.
Allora ho provato a leggere il link che hai postato, ma per ora ci ho capito poco, magari domani con la mente più lucida lo capirò meglio.
Intanto ho provato la soluzione da te suggeritami, al posto di FLOWID ho messo string, e in effetti gli errori si sono ridotti:


main.cpp: In function 'int main(int, char**)':
main.cpp: 178: error: no matching function for call to 'std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::end(char [8])' /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/include/g++-v4/bits/stl_set.h:300: note: candidates are: typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator std::set<_Key, _Compare, _Alloc>::end() const [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]
make: *** [main.o] Error 1

Alla riga 178 c'è l'if.
Io ho messo l'if così perché a quanto mi risulta il find punta all'elemento, se lo trova, altrimenti punta ad un elemento successivo all'ultimo, che ovviamente non esiste, e quindi scrivendo in quel modo l'if, è come se scrivessi: "Se l'elemento non esiste fai questo, altrimenti fai quest'altro".
Ho sbagliato anche quello?

EDIT: mi accorgo ora che ho sbagliato una parte del codice, la riposto qui perché non posso editare il primo messaggio:


#include <set>
#include <iostream>
#include <string>
#include <iterator>
using namespace std;

typedef char FLOWID 8

typedef set < string > IDF;

FLOWID fid;
int main()
{
fid = indirizzi_ip;
IDF idflow;
if(idflow.find(fid) == idflow.end(fid))
{
printf("L'indirizzo è nuovo ed è stato inserito nella lista.\n");
idflow.insert(fid);
}
else
printf("L'indirizzo è già presente nella lista.\n");
exit(0)
}

shodan
13-07-2011, 21:39
In pratica non puoi usare dei char* come parametro di un template.

idflow.end() non idflow.end(fid) [ mi era sfuggito prima ]
FLOWID che è?

L'if non è sbagliato se lo scopo è solo quello di informare. Ma come ho detto prima, se immetti nel set un elemento già presente, il set lo scarta da solo.
Per dare un'idea, se immetti in un set un intero libro, il set conterrà solo le 26 lettere dell'alfabeto più la punteggiatura e qualche numero se presente; l'if è interno.

Epiphone
13-07-2011, 22:02
Originariamente inviato da shodan
In pratica non puoi usare dei char* come parametro di un template.

idflow.end() non idflow.end(fid) [ mi era sfuggito prima ]
FLOWID che è?

L'if non è sbagliato se lo scopo è solo quello di informare. Ma come ho detto prima, se immetti nel set un elemento già presente, il set lo scarta da solo.
Per dare un'idea, se immetti in un set un intero libro, il set conterrà solo le 26 lettere dell'alfabeto più la punteggiatura e qualche numero se presente; l'if è interno.

FLOWID devo essermelo perso nell'edit perché nel primo post l'avevo messo, mannaggia a me. Fixato comunque.
Allora tolto fid dall'end e compila senza problemi. Solo che mi da l'if sempre vero.
Ma tornando al tuo esempio del libro, io immetto una coppia di indirizzi, sorgente e destinazione, e se uno dei due cambia allora la coppia deve essere trattata come diversa, altrimenti, se un pacchetto con stessa sorgente e stesso destinatario, mi dice che è già presente.
La differenza tra il mio caso e quello del libro è che nel mio caso io inserisco e confronto una stringa, mentre nel caso del libro inserisco i caratteri singolarmente, quindi se li trova li scarta e si ferma a 26 giusto?

shodan
13-07-2011, 22:46
Si, perché 26 sono le lettere dell'alfabeto. ma non centra se inserisci una stringa o un carattere: l'algoritmo è lo stesso perché si parla di un generico elemento.
Se inserisci "abracadabra" (in caratteri singoli) il set si comporta così:
inserisce a, inserisce b, inserisce r, scarta a perché c'è già, inserisce c, scarta a perché c'è già, inserisce d, scarta a perché c'è già...

Alla fine il set conterrà (in caratteri): abrcd

Se inserisci "192.168.1.100", "192.168.1.200","10.0.0.1","192.168.1.100"; il set conterrà solo il primi tre dal momento che il quarto lo trova già, ragione per cui il tuo if è sempre vero.
La cosa si applica anche alla map (che contiene coppie tipo: chiave - dato), tenendo presente che se durante l'inserimento viene rilevata una chiave doppia, la coppia viene scartata.
Il succo del discorso è che sia set sia map garantiscono l'univocità dei dati inseriti.

MItaly
13-07-2011, 22:50
Comunque, dovendo fare un set di indirizzi IP io li memorizzerei come una struct, o un intero a 32 bit o una union dei due, non come una stringa... anche solo per il fatto che il confronto di stringhe non va bene per gli IP: 192.168.0.1 e 192.168.000.1 sono lo stesso IP ma facendo un confronto di stringhe risultano diversi.

shodan
13-07-2011, 22:54
Senza contare che un confronto tra interi è molto più performante.

XAlbeX
13-07-2011, 22:58
Originariamente inviato da MItaly
Comunque, dovendo fare un set di indirizzi IP io li memorizzerei come una struct, o un intero a 32 bit o una union dei due, non come una stringa... anche solo per il fatto che il confronto di stringhe non va bene per gli IP: 192.168.0.1 e 192.168.000.1 sono lo stesso IP ma facendo un confronto di stringhe risultano diversi.

Aggiungerei anche che con interi a 32 bit il confronto è molto più veloce e la lista occupa meno memoria.

Epiphone
13-07-2011, 23:36
Originariamente inviato da shodan
Si, perché 26 sono le lettere dell'alfabeto. ma non centra se inserisci una stringa o un carattere: l'algoritmo è lo stesso perché si parla di un generico elemento.
Se inserisci "abracadabra" (in caratteri singoli) il set si comporta così:
inserisce a, inserisce b, inserisce r, scarta a perché c'è già, inserisce c, scarta a perché c'è già, inserisce d, scarta a perché c'è già...

Alla fine il set conterrà (in caratteri): abrcd

Se inserisci "192.168.1.100", "192.168.1.200","10.0.0.1","192.168.1.100"; il set conterrà solo il primi tre dal momento che il quarto lo trova già, ragione per cui il tuo if è sempre vero.
La cosa si applica anche alla map (che contiene coppie tipo: chiave - dato), tenendo presente che se durante l'inserimento viene rilevata una chiave doppia, la coppia viene scartata.
Il succo del discorso è che sia set sia map garantiscono l'univocità dei dati inseriti.

E questo è male! Devo rivederlo. Ho provato anche con il size prima e dopo l'insert, e poi confrontando i due valori, ma ovviamente, come dici tu, la situazione non cambia.

@MItaly: per brevità non ho postato come ho preso gli indirizzi, comunque la libreria pcap e li mappo in un array, tutto in automatico, quindi la formattazione è sempre la stessa (8 coppie di numeri esadecimali, 4 sorgente e 4 destinazione). Mi serve metterle così perché le uso per calcolarmi l'HMAC del pacchetto da usare come chiave per criptare lo stesso.
La parte del sapere se il pacchetto appartiene ad un flusso noto o meno è perché ho bisogno di sapere se devo mandare dei dati o no.

Cmq grazie a tutti. Ora cercherò di risolvere il problema di come fare a sapere se il dato era presente o è stato inserito.

Loading