Schreib/Lesezeiger auf bestimmte Zeile in Datei setzen?



  • CStoll schrieb:

    Da wundert es mich wirklich, daß dein Code dort oben keine SegFaults prozuziert.

    Mich nicht, er liest doch Zeiger wieder ein, die noch gültig (da noch in Scope) sind: Es wird test2 eingelesen. Dabei ist das, was eingelesen wird, natürlich Datenmüll. Aber dieser Datenmüll ist zufällig gültig, weil test1 noch existiert. Von daher ist kein Wunder, dass dieser spezielle Code „funktioniert“. Das, was der OP will, tut er natürlich trotzdem nicht.

    @CodeOriginator: Der Code ist, wie Du vielleicht schon entnommen hast, Müll. Dein Vorhaben klappt so nicht. Du musst für Deine Struktur einen spezifischen Ausgabe-Operator schreiben. Der Cast auf char* bringt nicht das, was Du Dir erwartest (sowas klappt nur mit POD).



  • Konrad Rudolph schrieb:

    CStoll schrieb:

    Da wundert es mich wirklich, daß dein Code dort oben keine SegFaults prozuziert.

    Mich nicht, er liest doch Zeiger wieder ein, die noch gültig (da noch in Scope) sind: Es wird test2 eingelesen. Dabei ist das, was eingelesen wird, natürlich Datenmüll. Aber dieser Datenmüll ist zufällig gültig, weil test1 noch existiert. Von daher ist kein Wunder, dass dieser spezielle Code „funktioniert“. Das, was der OP will, tut er natürlich trotzdem nicht.

    Daß das Einlesen hier zufällig klappt, kann ich durchaus verstehen, aber danach hätte ich einen SegFault erwartet, weil beide Objekte versuchen, diesen Speicher wieder freizugeben (double delete).



  • CStoll schrieb:

    Daß das Einlesen hier zufällig klappt, kann ich durchaus verstehen, aber danach hätte ich einen SegFault erwartet, weil beide Objekte versuchen, diesen Speicher wieder freizugeben (double delete).

    Ja, da haste auch wieder recht. 🙂



  • Danke Leute, wenn ich mir das durchdenke, muss ich euch Recht geben. Daher ist es auch kein Wunder, dass es jetzt bei mir im Projekt trotzdem nicht funktioniert. 🤡

    Könnt ihr mir bitte erklären, was PODs sind, und wie ich es besser machen kann? Danke im Voraus!



  • POD (Plain Old Data) sind kurz gesagt Datentypen, die aus einem C-Programm entsprungen sein könnten - das umfasst außer den build-in Typen (char, int, double etc) Structs/Klassen, die keine eigenen Konstruktoren, Destruktoren oder Zuweisungsoperatoren und nur POD-Elemente haben.

    Für dein Problem solltest du der Klasse einen eigenen operator<< (und operator>>) spendieren, der die Aus- und Eingabe übernimmt - die können auf die IO-Operatoren zurückgreifen, wenn du willst.



  • Okay, soweit komme ich noch klar. Habe mir den Artikel zu PODs bei Wikipedia durchgelesen. Wenn ich das ungefähr richtig verstanden habe, wäre dann die folgende Klasse, die einen platformunabhängigen 32 Bit Integer darstellt, auch eine Art POD? (Mal abgesehen vom Ctor, aber darf der zwangsläufig nicht dabei sein, um eine Klasse einen POD zu nennen?)

    #include <iostream>
    using namespace std;
    
    typedef unsigned char My32BitInteger[4];
    
    class MyInteger
    {
        private:
            My32BitInteger myInt;
    
        public:
            // Konvertierungsoperator
          operator int();
        // Standardkonstruktor
        MyInteger()
        {
            cout << "Standardkonstruktor" << endl;
            myInt[0] = 0;
            myInt[1] = 0;
            myInt[2] = 0;
            myInt[3] = 0;
        }
    
        // Konvertierungskonstruktor
        MyInteger( int i )
        {
            cout << "Konvertierungskonstruktor" << endl;
            myInt[0] = *( reinterpret_cast <char*> (&i)   );
            myInt[1] = *( reinterpret_cast <char*> (&i)+1 );
            myInt[2] = *( reinterpret_cast <char*> (&i)+2 );
            myInt[3] = *( reinterpret_cast <char*> (&i)+3 );
        }
    };
    
    // Konvertierungsoperator
    MyInteger:: operator int()
    {
         cout << "Konvertierungsoperator " << endl;
        return     *(reinterpret_cast <unsigned*> (myInt));
    }
    
    int main()
    {
        // Konvertierungskonstruktor
        MyInteger my_int( 77777777 );
        cout << my_int << endl;
    
        // Standardkonstruktor
         MyInteger my_integer;
    
        // Konvertierungsoperator
          int i = my_integer;
    
        cout << i << endl;
        my_integer = my_int;
    
        cout << my_integer << endl;
        getchar ();
        return 0;
    }
    

    CStoll, letztendlich stoße ich aber trotzdem auf das Problem, dass ich nicht weiß, wie ich nun eine Datenstruktur sicher in eine Datei abspeichere. Soll ich mich dann immer auf diese Klasse beziehen, also z.B. in.read (my_integer, sizeof (my_integer)); schreiben, oder wie soll ich das lösen?

    Edit, sorry muss mich berichtigen:

    Wikipedia schrieb:

    Plain Old Data Structures (PODS) are data structures [...]

    Nach der Aussage müsste meine test-Struktur (eine Seite vorher) eh schon ein POD sein. 😕



  • Diese Klasse könnte als POD durchgehen, deine frühere Beispielstruktur definitiv nicht (std::string kapselt die Verwaltung eines char-Zeigers und ist deshalb kein POD - das vererbt sich auch auf die Mutter-Klasse).



  • Hallo,

    Du kannst deiner Klasse doch read/write-Funktionen (binär) bzw. operator<< >> (text) spendieren, so dass sie sich selbst vernünftig lesen und schreiben kann. Dann ist diese Herumcasterei unnötig. Konvertierungsoperatoren sollte man sowieso nur dann erzeugen wenn sie absolut nicht zu vermeiden sind.



  • Also wenn ich anstatt std::string, char* nehme, wäre die Struktur also ein POD. Und das ist dann so okay, wenn ich nachfolgend mit der selben Methode ein und -aus lese?

    Braunstein schrieb:

    Du kannst deiner Klasse doch read/write-Funktionen (binär) bzw. operator<< >> (text) spendieren, so dass sie sich selbst vernünftig lesen und schreiben kann.

    Casten werde ich so oder so müssen, wenn auch nur klassenintern. Anlass für diese ganze Problematik war ja das Dateihandling auf Zeichen/ASCII -ebene, weshalb ich den Code in meinem Programm auf Byteorientierung umschreiben musste/muss, weshalb relativ wenig Zeit bliebt, eine Klasse dafür zu implementieren. Aber es wäre natürlich eine bessere Lösung, wiegesagt, wenn mir jetzt noch jemand erklären könnte, wie das mit den read/write Methoden intern aussieht, dann ist mir sehr geholfen. 🙂



  • write könnte so aussehen.

    void MyInteger::write(ostream& out)
    {
       out.write(reinterpret_cast<const char*>(myInt), sizeof(unsigned char));
       out.write(reinterpret_cast<const char*>(myInt+1), sizeof(unsigned char));
       out.write(reinterpret_cast<const char*>(myInt+2), sizeof(unsigned char));
       out.write(reinterpret_cast<const char*>(myInt+3), sizeof(unsigned char));
    }
    


  • CodeOriginator schrieb:

    Also wenn ich anstatt std::string, char* nehme, wäre die Struktur also ein POD. Und das ist dann so okay, wenn ich nachfolgend mit der selben Methode ein und -aus lese?

    Ja, dann wäre es ein POD - allerdings mußt du dich trotzdem selber darum kümmern, daß diese char-Zeiger auf intakte Daten verweisen - wenn du einfach die Adresse übernimmst, die beim letzten Programmlauf in die Datei geschrieben wurde, bekommst du nur Müll (und saubere char* Verarbeitung erfordert eigene Speicherverwaltung (Copy-Ctor/op=/Dtor) - damit bist du doch wieder bei einem Nicht-POD).

    Aber es wäre natürlich eine bessere Lösung, wiegesagt, wenn mir jetzt noch jemand erklären könnte, wie das mit den read/write Methoden intern aussieht, dann ist mir sehr geholfen. 🙂

    In deiner read/write kannst du natürlich die internen Daten binär speichern - wichtig ist nur, daß du alle relevanten Daten erwischst (bei Objekten variabler Größe gehören dazu auch die Größenangaben oder Endemarken), z.B.:

    class test
    {
      string data;
    public:
      void writeto(ostream& out)
      {
        size_t sz = data.size()
        out.write((char*)&sz,sizeof(size_t));
        out.write(data.c_str(),sz);
      }
      void readfrom(istream& in)
      {
        size_t sz;
        in.read((char*)&sz,sizeof(size_t));
        data.resize(sz);
        in.read(&data[0],sz);
      }
    };
    


  • Braunstein schrieb:

    write könnte so aussehen. [...]

    Hehe danke, dann bestätigt das meine Frage von vorhin.

    CStoll schrieb:

    (bei Objekten variabler Größe gehören dazu auch die Größenangaben oder Endemarken) [...]

    Geht klar, jetzt verstehe ich es 🙂 Ich werde versuchen, es zu implementieren, und parallel zum Funktionstest meine Klasse hier zu posten, um eine Bestätigung dafür zu erhalten, ob es so stimmt. Vorläufig schonmal vielen Dank!



  • Wenn ich sehe, daß beim binären Lesen und Schreiben (Serialisieren) von Strings immer wieder dieselben Probleme auftauchen, sollte man eigentlich der std::string-Klasse zwei Funktionen spendieren (als C++ Standard), welche diese (eigentlich simplen) Aufgaben übernehmen.
    Denn daß die beiden Stream-Operatoren << und >> der Klasse std::string eigentlich untauglich dafür sind (da sie quasi nicht "bijektiv" sind - wegen Whitespaces und fehlendem Endekennzeichen), läßt die Anfänger immer wieder in die selbe Programmierfalle laufen.



  • Bisher steht noch nichts in den C++0x Papers von solch einer Überlegung.... Wär aber definitiv eine gute Idee.



  • Ehrlich gesagt halte ich die string-Klasse schon jetzt für etwas groß. Die Funktionen wären schon praktisch, aber meiner Meinung nach nicht als Member, sondern eher in einer Art string_algorithm


Anmelden zum Antworten