Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: Xgamer 30. 04. 2011, 18:02:43
-
Zdravím, mam ulohu do školy na c++, v ktorom mam spravit serializáciu a deserializáciu objektu. Kedže som to nejako nevedel spraviť v tom mojom projekte tak som si vymyslel niečo jednoduchšie aby som to pochopil ale aj tak som nepochodil:)
Tu je kod:
#include <iostream>
#include <fstream>
using namespace std;
class Car
{
public:
Car(){};
Car(int w, int s, int p)
{
this->Weight = w;
this->MaxSpeed = s;
this->Price = p;
}
void setWeight(int w){ this->Weight = w;}
void setMaxSpeed(int s) {this->MaxSpeed = s;}
void setPrice(int p){this->Price = p;}
inline int getWeight() const {return Weight;}
inline int getMaxSpeed() const {return MaxSpeed;}
inline int getPrice() const {return Price;}
friend ostream& operator<<(ostream &os,Car &c);
private:
int Weight;
int MaxSpeed;
int Price;
};
ostream& operator<<(ostream &os,Car &c)
{
return(os << c.Weight << " " << c.MaxSpeed << " " << c.Price << endl);
}
class CarTrain
{
public:
CarTrain(){};
CarTrain(int s){this->size = s;this->carstore = new Car[size];}
void loadCar(int i,Car c){this->carstore[i] = c;}
Car getCar(int i){return this->carstore[i];}
int getSize(){return this->size;}
friend ostream& operator<<(ostream &os,Car &c);
void serialize(ostream& os)
{
Car tmp;
for(int i=0; i <this->size; i++)
{
tmp = this->carstore[i];
os << tmp;
}
}
CarTrain unserialize(ifstream& in)
{
CarTrain tmp; Car c;
int w,s,p;
tmp.size = this->size;
for(int i=0; i< this->size;i++)
{
in>>w;
in>>s;
in>>p;
c.setWeight(w);
c.setMaxSpeed(s);
c.setPrice(p);
tmp.loadCar(i,c);
}
return tmp;
}
private:
Car *carstore;
int size;
};
ostream& operator<<(ostream &os,CarTrain &ct)
{
Car tmp;
for(int i=0; i < ct.getSize(); i++)
{
tmp = ct.getCar(i);
os << tmp;
}
return os;
}
int main()
{
cout << "Serializacia a deserializacia" << endl;
Car c1(1000,150,8000);
Car c2(1200,190,9000);
Car c3(1400,220,120000);
CarTrain ct(10);
ct.loadCar(0,c1);
ct.loadCar(1,c2);
ct.loadCar(2,c3);
cout<<ct<<endl;
char *p = "ser.txt";
ofstream o;
o.open(p,ios::out);
ct.serialize(o);
o.close();
ifstream in;
in.open(p,ios::in);
CarTrain ct2 = ct.unserialize(in);
in.close();
return 0;
}
Problem je to že takto tá deserializácia nefunguje. Možno to bude aj tým že som asi uplne nepochopil pointu toho. A hlavne mam vyriešiť aj verzovanie objektov ale to nejako už vobec neviem:) Zatial som skušal textovu serializáciu. Poprosil by som niekoho kto sa tomu rozumie aby mi to trochu objasnil, resp. čo robim zle ..:) Ďakujem
-
Musis mat v tej triede CarTrain ukazatel na Car? Pretoze to by bolo uz trochu komplikovanejsie (a ak to tam musi byt, a mozes pouzivat 3rd party kniznice, tak odporucam boost). A btw za normalnych okolnosti this nemusis pouzivat, staci normalne meno premennej.
-
A potom ak budes chciet serializovat objekt (bez ukazatelov):
// serializacia
Car c1(1000,150,8000);
ofstream fout("subor"); // tu zalezi na systeme aky pouzivas - ak *nixy tak staci toto, ak widle tak treba pridat ako druhy parameter ios_base::binary
fout.write((char*) &c1, sizeof c1);
// deserializacia
Car c2;
ifstream fin("subor") // znova, mozno ze budes potrebovat ios_base::binary
fin.read((char*) &c2, sizeof c2);
-
Tohle ne... z víc důvodů.
Zde to bude fungovat, ale jakmile by tazatel použil virtuální funkce, tak by si zkopíroval i tabulku v. funkcí, což je to poslední, co by chtěl.
Nebo kdyby použil znakové proměnné a kompilátor si je přerovnal, popř. zarovnal - pak by sice přečetl, co zapsal, ale vždy jen tu jednou binárkou.
-
Nemám podmienku že to musí byť binarne :) to som chcel skusiť zo zaujimavosti, každopadne neviem spojazdniť ani textovu serializaciu:D 3rd knihovne použivať nemožem, ide o to že tu implementaciu si musim spraviť sam... Cielom je aby sa mi serializovala inštancia ct a potom deserializovala do inštancie ct2 v takom štýle mam aj šablonu pre program do školy. Ide že moj predpoklad bol to načitať ako obyčajný textový subor do nejakej premennej a nasledne tu premennu uložit do objektu typu CarTrain ale tak to nefunguje aj ked neviem prečo by nemalo. Hladal som aj na googli nejaky pekny priklad na niečo take ale všetko čom som našiel použiva knihovnu boost...
-
Ahoj, C++ som sice uz dlhsie nevidel, ale snad aspon trochu pomozem :)
1) Ked sa pozries na vytvoreny subor, tak je to spravne zaserializovane? Osobne predpokladam, ze asi ano, ale je vhodne to overit.
2) Vsimol som si, ze ked deserializujes, tak pouzivas objekt, ktory si serializoval. Obzvlast ide o toto:
tmp.size = this->size;Ak chces korektne serializovat, tak musis ulozit aj premennu size, resp. vsetky premenne v danom objekte.
3) Pride mi divne, ze inicializujes CarTrain na 10 a davas tam len 3 auta. Potom pri serializacii s tym moze byt problem (vsetko riadi premenna size, ktora bude 10 => (de)serializujes auta, o ktorych nic nevies, resp. su null)
Skus sa pozriet do toho suboru a uvidis, ci zle serializujes, alebo deserializujes. Ja osobne som kedysi vsetko riesil cez operator<< a operator>>. Vsetky premenne tam zapisat a potom opacne nacitat.
-
Hlavně si urči nějaké paradigma, jak se serializuje a deserializuje. IMHO správný postup je:
serializace probíhá operátorem >>
(možná bych preferoval metodu, ale to je jedno)
Deserializace objektu by měla být kontruktorem s parametrem stream (nemá smysl vytvořit prázdný objekt a pak ho přepsat vlastnostma ze streamu).
Serializace znamená vypsání všech hodnot objektu do streamu. Deserializace načtení. Z toho vyplývá, že každej objekt by měl mít serializační a deserializční metodu a např. car train by měl volat deserializaci jednotlivejch aut.
To, že deserializuješ auta v CarTrainu je imho važná chyba v návrhu, nejprve bych opravil tu. Pak bych nejprve odladil serializaci jednoho auta a pak teprve serializaci celého vlaku.
Tvůj problém je, že car deserializuješ v třídě carTrain. Proč? To je zo
-
PS: poslední věta mi tam omylem zůstala, nepatří tam... :-)
-
Ďakujem za tipy nejako som to spojazdnil ale ... aj tak tomu moc nerozumiem...:( a google mi nevypluje žiaden schopny priklad... Potreboval by som vidiet serializáciu uplne jednoducheho objektu potom mi to hadam dojde:D. Asi sa nejako stracam v tých streamoch. Aky je rozdiel medzi ifstream a istream?
-
class Integer
{
int value;
Integer(istream &is)
{
is >> value;
}
void serialize(ostream &os)
{
os << value;
}
};
Třeba takhle? Akorát to chce ještě ošetřit chyby (když se čtení nepovede) a další metody...
-
Ďakujem, a ako by to bolo pomocou tých preťažených operatorov?:) takto cez tie metody je jasne pochopitelne :) A čo je lepšie pretažit operatorov alebo urobiť si na to metody?
-
No na serializaci je to úplně jedno. Na deserializaci je imho vhodnější konstruktor, protože deserializací objekt "vznikne".
-
Pokud je tvuj kod stale takovy jako na zacatku, tak:
-michas serializaci a deserializaci ruznymi zpusoby, jednou je na to metoda pak pretizeny operator, zvol si jednu variantu, udelej ser. i deser., pokud je nutna i jina moznost, pouzij to jiz udelane, nedelej stejnou vec na dvou ruznych mistech.
-nerozkladej ser/deser mezi ruzne objekty, Car se musi umet serializovat i deserializovat. CarTrain opet serializuje a deserializuje sebe, jen svou strukturu, tj. pole (u tebe deserializuje i Car, co kdyz se Car zmeni?)
-chteji po tobe verzovani, tj. poznamenat si u serializovanych dat verzi sveho serializeru, je to dulezite kdyz se aplikace vyvyji a ty ulozis data ve stare verzi a ted je chces nacist novou verzi, nebo opacne, nekdo ulozil data v nove verzi, ty mas stale starou a ta nerozumi novym datum, staci na to integer hodnota kterou zvysis pri zmene struktury objektu a kterou deserializer musi nacist a porovnat, zda ji podporuje, muzes to mit na urovni aplikace
- a moc neverim ze ti to funguje, podle mne to musi padnout na nepovoleny pristup do pameti, v metode CarTrain::deserialize(...) mas
CarTrain tmp; Car c;
tmp.size = this->size;
...
tmp.loadCar(i,c);
tmp poziva defaultni, nebo bezparametrovy konstruktor, telo konstruktoru mas prazdne, vnitrni promenne neinicializovane, zadne pole Car[] jsi tedy nealokoval, ale carstore ukazuje buh vi kam, to ze nastavis size neudela nic a pak pouzijes loadCar pro prepsani polozky s indexem i, no podle mne -> zuch.
Tak to jen tak par poznamek.
-
Tukan: s tím, že to musí být stejně zásadně nesouhlasím, serializace a deserializace není inverzní operace. Serializací totiž objekt nezaniká, zatímco deserializací vzniká. Proto by to mělo být asymetrické (konstruktor versus metoda/operátor).
-
Ďakujem za tie poznamky ;) Z takých veci sa človek najviac nauči, ano je pravda že som nealokoval pamät pre to carstore... to bol hlavny problem prečo to vobec nefungovalo. Tá serializácia a deserializácia je stale pre mna tak trochu zahada ale vdaka vašim prispevkom
v tom už mam jasnejšie :)
-
Tukan: s tím, že to musí být stejně zásadně nesouhlasím, serializace a deserializace není inverzní operace. Serializací totiž objekt nezaniká, zatímco deserializací vzniká. Proto by to mělo být asymetrické (konstruktor versus metoda/operátor).
Je zbytečné dělat serializaci a deserializaci asymetricky, ony jsou totiž z hlediska toho objektu totožné. Takhle to třeba řeším já:
class Example
{
public:
Example()
: first(1)
, second(2)
{}
template <class T>
Example(Serialize::Construct /* Tag, který říká, že jde o deserializaci */, T &archive)
{
this->serialize(archive);
}
template <class T>
void serialize(T &archive)
{
archive & this->first;
archive & this->second;
//...
}
protected:
std::size_t first;
std::size_t second;
};
-
Čau Stene.
K serializačním konstruktorům jsem se zatím ještě nedostal, spíš to řeším tak, že objekty jsou konstruované v základním (výchozím) tvaru. To nutně nemusí znamenat, že musí mít defaultní konstruktor. Ale myšlenkou je, že serializací se zaznamenává stav nějakých objektů a deserializací se ten stav obnovuje. Tedy nejprve se objekty zkonstruují ve výchozím stavu a pak se jim ten stav změní.
Proč jsi v původním mém konceptu změnil operator () na operator &? On se operátor () dá použít i jako volání funktoru.
-
Původního tazatele bych možná odkázal na mou teoretickou (bohužel nedokončenou) práci na téma Serializace v C++ ve formě seriálu:
http://bredy.novacisko.cz/?g=main&kat=59
-
Čau Stene.
K serializačním konstruktorům jsem se zatím ještě nedostal, spíš to řeším tak, že objekty jsou konstruované v základním (výchozím) tvaru. To nutně nemusí znamenat, že musí mít defaultní konstruktor. Ale myšlenkou je, že serializací se zaznamenává stav nějakých objektů a deserializací se ten stav obnovuje. Tedy nejprve se objekty zkonstruují ve výchozím stavu a pak se jim ten stav změní.
Proč jsi v původním mém konceptu změnil operator () na operator &? On se operátor () dá použít i jako volání funktoru.
Serializační konstruktor je celkem jednoduchý na napsání (je nutné dát pozor na věci, co se musí vyplnit už v konstruktoru, aby byly serializovány ve stejném pořadí, v jakém je konstruktor vytáhne) a hodí se do míst, kdy objekt nemůže mít defaultní konstruktor (třeba semafory sdílené podle jména nebo pokud objekt obsahuje konstantní položky). Dalo by se to řešit obalem přes pointer, ale když jsem z htmlcxx ukradl takové jednoduché řešení, jak značkovat použití obecné šablony, tak proč si to ztěžovat :-)
operator & jsem omylem použil tady, používá ho Boost.Serialization a občas s tím pracuju. Jinak taky používám operator (), hlavně kvůli tomu, že většinu serializací provádím do JSONu a tam často potřebuju mít dva parametry (klíč a hodnotu).
-
Původního tazatele bych možná odkázal na mou teoretickou (bohužel nedokončenou) práci na téma Serializace v C++ ve formě seriálu:
http://bredy.novacisko.cz/?g=main&kat=59
Ďakujem, to vyzera celkom pekne napisane ;) určite so to prečitam:)
-
Serializační konstruktor je celkem jednoduchý na napsání (je nutné dát pozor na věci, co se musí vyplnit už v konstruktoru, aby byly serializovány ve stejném pořadí, v jakém je konstruktor vytáhne) ...
Ano, a to je přesně o tom. Totiž, pokud chci využit deserializační konstruktor, musí i member proměnné (a to tedy všechny) používat deserializační konstruktory, musí být ve správném pořadí (a nejsem si jist, jestli pořadí inicializace je v normě C++ zaručeno), nebo v druhé variantě se ti to rozpadne na dvě části, což jsi ukázal v příkladu.
- konstrukce ve výchozím stavu
- deserializace, která stav změní.
Není to až tak velká výhoda, aby se vyplatilo zahazovat oboustrannost serializace ... "i zvenku" (z API ... vlastně máš tady dvě metody místo jedné, byť vnitřně se z druhé volá první)
-
K serializačním konstruktorům jsem se zatím ještě nedostal, spíš to řeším tak, že objekty jsou konstruované v základním (výchozím) tvaru. To nutně nemusí znamenat, že musí mít defaultní konstruktor. Ale myšlenkou je, že serializací se zaznamenává stav nějakých objektů a deserializací se ten stav obnovuje. Tedy nejprve se objekty zkonstruují ve výchozím stavu a pak se jim ten stav změní.
Serializaci má (podle mě) velice hezky vyřešenou fox toolkit. Nejen že používá serializační konstruktory, ale přetěžuje i operátory tříd datových proudů, takže stačí otevřít serializační soubor a pomocí operátorů << >> serializaci provést. Navíc samotná serializace konkrétních objektů se implemetuje přetížením metod load( ) a save( ) u všech potomků třídy FXObject, a mělo by být teoreticky možné využít k realizaci těchto metod místo přetížených operátorů streamů. Někomu se však může zdát jako nevýhoda, že celý tento mechanizmus je řešen pomocí klasických maker.
-
Serializaci má (podle mě) velice hezky vyřešenou fox toolkit. Nejen že používá serializační konstruktory, ale přetěžuje i operátory tříd datových proudů, takže stačí otevřít serializační soubor a pomocí operátorů << >> serializaci provést. Navíc samotná serializace konkrétních objektů se implemetuje přetížením metod load( ) a save( ) u všech potomků třídy FXObject, a mělo by být teoreticky možné využít k realizaci těchto metod místo přetížených operátorů streamů. Někomu se však může zdát jako nevýhoda, že celý tento mechanizmus je řešen pomocí klasických maker.
No nevím, přečti si můj seriál, mou zvolená metoda má prostě opodstatnění. A není to žádný ad-hoc řešení. První verze serializátoru vznikla někdy v roce 2002 a byť se od toho posledního návrhu velice liší, ten vývoj byl celkem bouřlivý. Úspěšně jsem to nasadil například v některých částech fulltextu (v Seznamu), Lištička to používá pro serializaci zpráv mezi okny prohlížeče IE, později jsem napsal i vlastní RPC protokol, nebo serializaci do XML streamu.