stack<string> mit fstream speichern



  • hi, ich habe eine objekt vom typ stack<string> und möchte dieses wie schon in dem titel gesagt abspeichern.
    meine überlegungen waren:

    stack<string> Stack
    
    ....
    
    Stack.open("Stack.dat", ios::out|ios::binary);
    Stack.write(&Stack, sizeof(Stack));           //Fehler
    Stack.close();
    

    dabei bekomme ich aer leider folgende fehlermeldung die ich nicht richtig deuten kann:

    Fehler: keine passende Funktion für Aufruf von »std::basic_fstream<char, std::char_traits<char> >::write(std::stack<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::deque<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >*, unsigned int)«

    an was liegt das? ich hab gehört das es probleme beim speichern von strings mit dieser methode gibt, da der inhalt in der stringklasse nur per pointer referenziert ist und daher nicht mit gespeichert wird.

    was kann man da machen?



  • Hi staxx,

    erstens hast du vermutlich einen Namenskonflikt.

    Ist Stack jetzt deine Datei oder dein Stack-Objekt.

    Zudem musss ich dir leider sagen, dass es in C++ keine Standard-Serialisierung gibt.

    Du mußt dich selbst darum kümmern, wie deine Objekte in den Stream geschrieben
    und wieder ausgelesen werden.

    Gruß,
    CSpille



  • ups, ja hast recht, das mit dem namen hab ich garnicht gesehnen.
    ich meine das natürlich so:

    stack<string> Stack;
    fstream StackFile;
    
    ....
    
    StackFile.open("Stack.dat", ios::out|ios::binary);
    StackFile.write(&Stack, sizeof(Stack));           //Fehler
    StackFile.close();
    

    Du mußt dich selbst darum kümmern, wie deine Objekte in den Stream geschrieben
    und wieder ausgelesen werden.

    das versteh ich nicht ganz, hier ist doch gar nichts mit streams?



  • Hi staxx,

    StackFile ist ein fstream.

    ich dachte da an sowas:

    // EDIT: Hier kannste auch ne Template-Funktion draus machen
    std::ostream& operator <<(std::ostream& s, const stack<std::string>& st){
    st.writeToStream(s);
    
    }
    
    template<typename T> stack{
    
    void writeToStream(std::ostream& s){
        //Wahrscheinlich wirst du keinen std:vector haben, aber soll ja nur ne Skizze sein
        s << vec.size();
        for(typename std::vector<T>::iterator it = vec.begin; it!=vec.end(); ++it){
            s << (*it);
        }
    }
    
    }
    
    stack<std::string> Stack;
    fstream StackFile;
    
    ....
    
    StackFile.open("Stack.dat", ios::out|ios::binary);
    StackFile << Stack;
    StackFile.close();
    

    Ich hoffe du weißt jetzt ungefähr, was ich meine...

    Gruß,
    CSpille



  • Hi staxx,

    was mir gerade kommt, willst du stack aus der Standard-Library serialisieren.

    Dann kannste das natürlich nicht in ne Memberfunktion machen.

    Gruß,
    CSpille



  • Hi staxx,

    ich hab mit nochmal Gedanken über deine Frage gemacht und bin zu der Erkenntnis
    gekommen, dass es nicht clever ist den operator << zu überschreiben.

    Deswegen schlag ich mal so ne Lösung für deque vor, denn stack
    ist zum serialisieren wirklich ne blöde Datenstruktur ^^:

    #include <deque>
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <vector>
    
    template<typename T> void serialize(std::ostream& s, const T& i){ 
    	s.write((char*)&i, sizeof(T));
    }
    
    template<typename T> void deserialize(std::istream& s, T& i){
    	s.readsome((char*)&i, sizeof(T));
    }
    
    void serialize(std::ostream& s, const std::string& str){ 
    	size_t i = str.length();
    	serialize(s, i);
    	s.write(str.c_str(), i);
    }
    
    void deserialize(std::istream& s, std::string& str){
    	size_t i;
    	deserialize(s, i);
    	char* c = (char*)malloc(i+1);
    	s.readsome(c, i);
    	c[i] = '\0';
    	str = c;
    	free(c);
    }
    
    template<typename T> void serializeList(std::ostream& s, const T& deque){
    	size_t i = deque.size();
    	serialize(s, i);
    	for(typename T::const_iterator it = deque.begin(); it!=deque.end(); ++it){
    		serialize(s, *it);
    	}
    }
    
    template<typename T, typename L> void deserializeList(std::istream& s, L& deque){ 
    	size_t i;
    	for(deserialize(s, i); i>0; --i){
    		T value;
    		deserialize(s, value);
    		deque.push_back(value);
    	}
    }
    
    int main(int argc, char *argv[]){
    	std::deque<std::string> myDeque;
    	myDeque.push_back("How to");
    	myDeque.push_back("serialize");
    	myDeque.push_back("a deque");
    	std::fstream outFile("/deque.dat", std::ios::out|std::ios::binary); 
    	serializeList(outFile, myDeque);
    	outFile.close();
    
    	myDeque.clear();
    
    	std::fstream inFile("/deque.dat", std::ios::in|std::ios::binary);
    	deserializeList<std::string, std::deque<std::string> >(inFile, myDeque);
    	inFile.close();
    
    	std::cout << myDeque.back() << std::endl;
    	myDeque.pop_back();
    	std::cout << myDeque.back() << std::endl;
    	myDeque.pop_back();
    	std::cout << myDeque.back() << std::endl;
    	myDeque.pop_back();
    
    	std::vector<unsigned int> vec;
    	vec.push_back(54);
    	vec.push_back(74);
    	vec.push_back(90);
    	std::fstream outFile2("/vec.dat", std::ios::out|std::ios::binary); 
    	serializeList(outFile2, myDeque);
    	outFile2.close();
    
    	myDeque.clear();
    
    	std::fstream inFile2("/vec.dat", std::ios::in|std::ios::binary);
    	deserializeList<unsigned int, std::vector<unsigned int> >(inFile2, vec);
    	inFile2.close();
    
    	std::cout << vec.back() << std::endl;
    	vec.pop_back();
    	std::cout << vec.back() << std::endl;
    	vec.pop_back();
    	std::cout << vec.back() << std::endl;
    	vec.pop_back();
    
        return 0;
    }
    

    EDIT: Die Listen auch noch als Template

    Gruß,
    CSpille



  • wow, vielen dank für die mühe! es klappt wunderbar.

    bloß was ich noch nicht hinkriege(was aber nix mit deinem code, sondern mit meiner unkenntnis über deque zu tuen hat) ist folgendes:

    deque<string> Deq;
    string Str;
    
    ....
    
    if(!Deq.emty())
    {
            cout << Deq.back() << endl;   //das funktioniert
    }
    if(!Deq.empty())
    {
            Str = Deq.back();    //hier bleibt das programm einfach stehen
    }
    

    wieso bleibt da das programm stehen? ich mein eine fehlermeldung beim compilieren oder sogar in der laufzeit könnt ich eher verstehen, aber garnichts?
    aber was viel wichtiger ist: was ist falsch? und was kann ich machen damit es funktioniert?
    ich hab mir schon im internet was zu deque angeschaut, aber nichts brauchares gefunden.



  • Hi staxx,

    abgesehen von deinem Tippfehler ^^ (, der natürlich einen Compilerfehler
    hervorufen würde), fällt mir in dem geposteten Code kein Fehler auf.

    Wahrscheinlich führt Code davor zu einem undefinierten Verhalten (oder so).

    Ich bin jetzt aber auch kein C++-Profi, dennoch bin ich ziemlich sicher,
    dass der Code fehlerfrei ist (oder ich gerade völlig blind ^^)

    Gruß,
    CSpille



  • jup, du hattest recht, es lag nicht an der zuweisung, sondern an anderen code. bloß leider wurde das problem durch deinen code hervorgerufen.

    das problem ist das der deque nicht richtig geladen wird, damit meine ich das die enthaltenen strings nicht alle richtig sind. das heißt das die ersten leer sind, dann einige zerstückelt und teilweise falschen zeichen am ende, und die letzten sind immer richtig.

    hier kann ich aber 100%ig sagen das es nicht an meinem anderen code liegt da ich erst den deque befülle, und dann langsam wieder abarbeite. dazu wird er von zeit zu zeit zur sicherheit gespeichert damit die laufzeit unterbrechen kann und später das programm an der selben stelle(bzw. der wo die letzte sicherungskopie des deque angelegt wurde) fortsetzen kann.
    daher: wenn ich das program ganz normal durchlaufen lasse gibt es keine probleme, wenn es aber mit dem neu geladenen deque arbeitet treten fehlerhate strings auf.



  • Sorry staxx,

    keine Absicht...

    In Zeile 77 und 80 muss natürlich vec hin und nicht myDeque.

    Aber sonst kann ich keinen Fehler entdecken. 😞



  • also ich hab deinen code 1:1 übernommen und jediglich das std:: überall weggenommen(da using namespace std;)
    auch den code zum laden und speichern hab ich genauso übernommen(natürlich mit anderen namen eingesetzt)
    jetzt hab ich halt immernoch das problem das in dem aus der geladenen datei die strings im deque zt. fehlerhaft oder leer sind, welches bei dem vom programm in der laufzeit selber generierte deque funktioniert.



  • hinzuzufügen wäre vielleicht noch das auf den deque bei meinen tests ca. 1000-2000 einträge kommen. eigentlich denk ich mir das das egal sein müsste, aber vielleicht ist es das ja doch nicht.


Anmelden zum Antworten