Entra

View Full Version : [c++]come posso salvare le map?


NA01
06-05-2005, 17:18
ho un bel programmino che fa un sacco di cose inutili. l'ultima cosa che sarebbe carino implementare è il salvataggio di tutti i dati su hd e la lettura all'avvio successivo.

il problema è che uno dei tipi è contenitire standard map.
ho provato (senza crederci) a metterlo su file come se fosse un tipo standard, ma credo giustamente il compilatore mi ha urlato di tutto....
come posso mettere tutti i dati su hd?


ciao!

NA01
07-05-2005, 10:12
:cry:

Fenomeno85
07-05-2005, 10:25
per forza devi usare i file :D quindi mi sa che avevi sbagliato a implementare :D

~§~ Sempre E Solo Lei ~§~

fek
07-05-2005, 11:45
ho un bel programmino che fa un sacco di cose inutili. l'ultima cosa che sarebbe carino implementare è il salvataggio di tutti i dati su hd e la lettura all'avvio successivo.

il problema è che uno dei tipi è contenitire standard map.
ho provato (senza crederci) a metterlo su file come se fosse un tipo standard, ma credo giustamente il compilatore mi ha urlato di tutto....
come posso mettere tutti i dati su hd?


ciao!


typedef std::map<std::string, std::string> StringMap;

void SaveMap(StringMap stringMap)
{
FILE fout = fopen("stringmap.txt", "wt");
if (fout == NULL)
return;

StringMap::iterator pos = stringMap.begin();
StringMap::iterator end = stringMap.end();

for (; pos != end; ++pos)
{
fprintf(fout, "%s %s\n", pos->first, pos->second);
}

fclose(fout);
}



Ti ho fatto un esempio con mappe di stringhe ma puoi semplicemente convertire i tipi che usi per chiave e valore a stringhe e poi salvarli in un file di testo riga per riga.
Per legge il file, leggi riga per riga, converti la prima stringa al tipo chiave, la seconda stringa al tipo valore e inserisci nella mappa.

Quest'operazione si chiama serializzazione e deserializzazione di un tipo (la mappa).

NA01
07-05-2005, 14:46
funzia grazie, ridarò un'occhiata al capitolo sugli iteratori :mc:

una curiosità.
in molti esempi (come nel tuo) di listati in c++ l'accesso a file viene implementato con le funzioni del c di stdio e non con gli stream del c++....

c'è un motivo particolare?

ciao!

NA01
09-05-2005, 18:29
ok, ho modificato la tua funzione e ho riprovato a fare la deserializzazione.
casini assurdi sulle string :muro: :muro:
vi dò tutto il sorgente per il salvataggio (incompleto e la gestione degli errori è da rifare, ma non importa per il momento)


#include <iostream>
#include <string>
#include <map>
#include <fstream>

using namespace std;

typedef map<string,int> StringMap;
class file_state{};

void SaveMap(StringMap string ,char* file)
{
file_state bad_file;
ofstream out(file,ios_base::binary);
StringMap::iterator pos = string.begin();
StringMap::iterator end = string.end();
for (; pos != end; ++pos){
out << pos->first << "\n" << pos->second <<"\n";
}
if(out.good() == false){
throw(bad_file);
}
out.close();
}

void ReadMap(StringMap string ,char* file)
{
file_state bad_file;
ifstream in(file,ios_base::binary);
StringMap::iterator pos = string.begin();
StringMap::iterator end = string.end();
for (; pos != end; ++pos){
in.getline(pos->first,500,"\t");
in >> /*(string)(pos->first) >>*/ pos->second;
}
if(in.good() == false){
throw(bad_file);
}
in.close();
}



la Save funziona, l'altra.....ho provato in un sacco di modi, ho fatto cast ma non mi vuole leggere quella porca di una string

si vede che è da due anni che non metto mano seriamente al c++ :mc: :sofico:
help!

ciao

cionci
09-05-2005, 19:11
ifstream in(file,ios_base::binary);
StringMap::iterator pos = string.begin();
StringMap::iterator end = string.end();
for (; pos != end; ++pos){
in.getline(pos->first,500,"\t");
in >> /*(string)(pos->first) >>*/ pos->second;
}

Ma come puoi fare in questo modo se string è vuota ???? string la devi passare per riferimento... Se la passi per copia i valori inseriti nel chiamante non li vedi...

pair<string, int> tmp;
while(!in.eof())
{
in >> tmp.first >> tmp.second;
string.insert(tmp);
}

Attento all'eof...forse c'è da gestirlo in maniera diversa...

NA01
09-05-2005, 20:16
scusa, non vorrei romperti troppo le balle, ma ho qualche domanda

- perchè usi insert sul template tmp?

- a me il problema lo dà >> pos->first non me lo compila....

- alla fine della tua procedura che faccio?
ritorno l'indirizzo di tmp?


grazie della pazienza

ciao!

cionci
09-05-2005, 23:23
Non devi ritornare l'indirizzo di string perchè devi passare string per riferimento (come ho scritto sopra)...
Uso la insert perchè tmp è un Pair che va inserito nel Map...quando crei un coppia di dati per inserirli nel Map solitamente si usa questo metodo...o più generalmente questo:

typedef pair<String, int> StringPair;

string.insert(StringPar("a", 1));
string.insert(StringPar("b", 2));

Sul fatto che non ti compili così ad occhio non ti so dire perchè, ma in quel caso pos == end (string è vuota) e quindi comunque non otterresti niente... Devi prendere come riferimento la fine del file per immettere i dati nel map...ed il tipo di dati che si immette in un map di default è un pair con lo stesso template del map...

fek
10-05-2005, 11:23
Non devi ritornare l'indirizzo di string perchè devi passare string per riferimento (come ho scritto sopra)...
Uso la insert perchè tmp è un Pair che va inserito nel Map...quando crei un coppia di dati per inserirli nel Map solitamente si usa questo metodo...o più generalmente questo:

typedef pair<String, int> StringPair;

string.insert(StringPar("a", 1));
string.insert(StringPar("b", 2));


Io che sono pigro in genere uso std::make_pair:

string.insert(std::make_pair("a", 1));
string.insert(std::make_pair("b", 2));

fek
10-05-2005, 11:37
- a me il problema lo dà >> pos->first non me lo compila....


Mi posti l'errore di compilazione?


- alla fine della tua procedura che faccio?
ritorno l'indirizzo di tmp?


Fai come ti ha detto cionci, passa StringMap per reference, cosi':


void ReadMap(StringMap& string ,char* file) // per riferimento
{
file_state bad_file;
ifstream in(file,ios_base::binary);

while(!in.eof())
{
string name;
int id;

in >> name >> id;
string.insert(std::make_pair(name, id));
}

in.close();
}


"string" (per altro non e' un buon nome, perche' e' una mappa di stringhe non una sola stringa) conterra' la mappa aggiornata perche' e' passato per riferimento.

NA01
10-05-2005, 15:12
"string" (per altro non e' un buon nome, perche' e' una mappa di stringhe non una sola stringa) conterra' la mappa aggiornata perche' e' passato per riferimento.


già, motivo per cui non avevo capito il codice di cionci (prima metto nomi idioti, poi non me ne ricordo) e per cui non ne avevo nemmeno capito il suggerimento.
passare una sting per valore quando io volevo una map... non aveva senso, se non nella con la mia idiozia nello scegliere i nomi :mbe: :sofico:

ecco l'errore:

file.cpp: In function `void ReadMap(StringMap*, char*)':
file.cpp:34: error: 'class std::map<std::string, int, std::less<std::string>,
std::allocator<std::pair<const std::string, int> > >' has no member named '
first'
file.cpp:34: error: 'class std::map<std::string, int, std::less<std::string>,
std::allocator<std::pair<const std::string, int> > >' has no member named '
second'


ho risolto piazzando i dati in due variabili temporanee e poi passandole così

stringa[str] = integer;


che però giustamente se passo un puntatore non funziuona più :muro:
userò ala tua!

grazie, ciao!

cionci
10-05-2005, 15:18
Strano...mi fai vedere come era il codice ?

void ReadMap(StringMap*, char*)

Comunque perchè passi per indirizzo quando hanno inventato appositamente il passaggio per riferimento ? ;) Poi all'atto pratico è la stessa cosa...ma visto che esiste sfruttiamolo...