Serializácia a deserializácia C++

Serializácia a deserializácia C++
« kdy: 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:
Kód: [Vybrat]
#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


asd

Re: Serializácia a deserializácia C++
« Odpověď #1 kdy: 30. 04. 2011, 21:42:30 »
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.

asd

Re: Serializácia a deserializácia C++
« Odpověď #2 kdy: 30. 04. 2011, 23:47:31 »
A potom ak budes chciet serializovat objekt (bez ukazatelov):

Kód: [Vybrat]
// 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);

Tomášek

Re: Serializácia a deserializácia C++
« Odpověď #3 kdy: 01. 05. 2011, 00:28:02 »
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.

Re: Serializácia a deserializácia C++
« Odpověď #4 kdy: 01. 05. 2011, 08:26:04 »
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...


Re: Serializácia a deserializácia C++
« Odpověď #5 kdy: 01. 05. 2011, 11:08:02 »
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:
Kód: [Vybrat]
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.

Logik

  • *****
  • 1 022
    • Zobrazit profil
    • E-mail
Re: Serializácia a deserializácia C++
« Odpověď #6 kdy: 01. 05. 2011, 13:19:52 »
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



Logik

  • *****
  • 1 022
    • Zobrazit profil
    • E-mail
Re: Serializácia a deserializácia C++
« Odpověď #7 kdy: 01. 05. 2011, 13:21:09 »
PS: poslední věta mi tam omylem zůstala, nepatří tam... :-)

Re: Serializácia a deserializácia C++
« Odpověď #8 kdy: 01. 05. 2011, 15:07:32 »
Ď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?

Logik

  • *****
  • 1 022
    • Zobrazit profil
    • E-mail
Re: Serializácia a deserializácia C++
« Odpověď #9 kdy: 01. 05. 2011, 16:48:21 »
Kód: [Vybrat]
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...


Re: Serializácia a deserializácia C++
« Odpověď #10 kdy: 01. 05. 2011, 17:01:54 »
Ď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?

Logik

  • *****
  • 1 022
    • Zobrazit profil
    • E-mail
Re: Serializácia a deserializácia C++
« Odpověď #11 kdy: 01. 05. 2011, 17:06:02 »
No na serializaci je to úplně jedno. Na deserializaci je imho vhodnější konstruktor, protože deserializací objekt "vznikne".

Tukan

Re: Serializácia a deserializácia C++
« Odpověď #12 kdy: 01. 05. 2011, 18:49:57 »
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.

Logik

  • *****
  • 1 022
    • Zobrazit profil
    • E-mail
Re: Serializácia a deserializácia C++
« Odpověď #13 kdy: 01. 05. 2011, 20:50:47 »
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).

Re: Serializácia a deserializácia C++
« Odpověď #14 kdy: 01. 05. 2011, 21:24:01 »
Ď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 :)