STL copy [Gelöst]



  • Ok. Mit Templates habe ich mich noch nicht beschäftigt.

    Meinen Vorschlag hatte ich im Vorfeld schon ausprobiert, leider kompiliert der Code nicht.

    //Überladung von Operatoren, auch im Zusammenhang mit STL-Copy
    #include <iostream>
    #include <vector>
    #include <fstream>
    #include <iterator>
    #include <algorithm>
    
    using namespace std;
    
    class Spieler
    {
        public:
        int geld;
    };
    
    //ostream& operator<<(ostream &os,Spieler &p)
    //edit: richtig ist:
    ostream& operator<<(ostream &os,const Spieler &p)
    {return os<<p.geld;}
    
    istream& operator>>(istream &os,Spieler &p)
    {return os>>p.geld;}
    
    int main()
    {
        Spieler a;
        vector<Spieler>myVector;
        cin>>a;
        myVector.push_back(a);
        cout<<myVector[0];
        cout<<"\n"<<a;
        fstream filestream("test.txt",ios::out|ios::trunc);
        if(!filestream)
        {return 20;}
        copy(myVector.begin(),myVector.end(),ostream_iterator<Spieler>(filestream));
        //filestream.close();
        return 0;
    }
    


  • Bei operator << muss es const Spieler& heißen. (Du kannst übrigens auch ostream_iterator<Spieler>(cout) schreiben, das scheint mir leicher zum Debuggen.)



  • Jupp. Jetzt funktioniert es. Danke für den Tip.

    Warum muß man eigentlich das "const" setzen?
    Normalerweise ist das doch optional oder?

    Und wenn beim "<<" warum dann nicht beim ">>"?



  • redrew99 schrieb:

    Warum muß man eigentlich das "const" setzen?

    Google nach "const-correcness". Hier kurz:
    Alles was ich für Pointer schreibe gilt gleichermaßen für Referenzen:

    const char* p; // Gelesen "pointer to const char"
    char const* p; // Daher schreiben einige das so, jetzt kann man den Typ rückwärts lesen.
    char* const p; // Jetzt ist der Pointer konstant, nicht das worauf er zeigt.
    
    void foo(const int); // Nicht unbedingt sinnvoll, das const gibt dem Aufrufer keinerlei Informationen.
    void foo(const char* p); // Wichtig! Das garantiert dem Aufrufer, dass die Dinge auf die p zeigt nicht geändert werden. 
                             // Falls das möglich ist, ist es char* gegenüber zu bevorzugen.
    
    struct Foo
    {
      void foo() const; // Das macht "this" const. Es können keine* Membervariablen geändert werden, 
                       // Und keine nicht const Methoden aufgerufen werden, da this ja jetzt const Foo* ist.
      void bar(); // foo könnte bar nicht aufrufen.
    };
    
    void foo(const Foo* f)
    {
      f->foo(); // Ok
      f->bar(); // pum, Fehler
    }
    

    Dafür ist übrigens const_cast, den man aber wirklich mit Bedacht einsetzen sollte. const_cast kann auch nur das worauf Referenzen und Pointer zeigen "ent-consten". Ein cast auf z.B. ein const int wäre nicht möglich. (Und würde bei Zuweisung auch in undefiniertem Verhalten enden.)



  • Hmm, ok. Werde mir das mal in Ruhe anschauen. Auch const-correctness.
    Generell verstehe ich schon, warum das das Setzen von "const" sinnvoll ist,
    nur warum es z.B. wie hier bei "<<" gesetzt werden muß, hingegen bei ">>" nicht,
    ist mir zur Zeit noch ein Rätsel.

    Jetzt werde ich erstmal pennen gehen. Morgen ist auch noch ein Tag.



  • redrew99 schrieb:

    bei ">>" nicht,

    Bei der Funktion änderst du doch das Objekt hinter der Referenz. Denkst du nicht, dass es etwas stören würde, wenn dieses Objekt jetzt konstant wäre? 😉



  • Stimmt, Du hast natürlich recht. Durch die ganze Sucherei wegen dem fehlenden "const" hatte ich ein Brett vor dem Kopp.

    Aber warum man zwingend das "const" bei "<<" setzen muß, ist mir nicht ganz klar,
    oder es gibt keine vorstellbare Situation, wo das übergebene Objekt noch geändert werden soll ?



  • Damit gibst du dem Aufrufenden die Garantie, dass du es nicht änderst. Stichwort: const correctness



  • Edit: gelöscht.



  • redrew99 schrieb:

    muß, ist mir nicht ganz klar,
    oder es gibt keine vorstellbare Situation, wo das übergebene Objekt noch geändert werden soll ?

    von einem Ausgabeoperator erwarte ich, dass er ein bestimmtes Objekt ausgibt. Wieso sollte er das Objekt dafür ändern?

    Felix



  • redrew99 schrieb:

    oder es gibt keine vorstellbare Situation, wo das übergebene Objekt noch geändert werden soll ?

    Klar kann man sich Situationen vorstellen, wo das Objekt noch verändert wird. Das fällt dann unter die Kategorie Designfehler. Denn erstens ist das völlig unerwartet (oder rechnest du damit, dass ein Objekt seinen sichtbaren1 Status ändert, wenn du es ausgibst?), zweitens verletzt das dann das SRP, denn einzige Aufgabe des op<< ist, eine Repräsentation des Objekts in den Stream zu schreiben und nicht, es zu verändern.

    _______________
    1 es mag interne Daten geben, die nicht zum sichtbaren Zustand gehören, die durchaus auch von irgendwelchen komplexeren Ausgabeoperationen angefasst werden könnten. Solche Daten gehören aber mutable deklariert und damit immernoch const für den op<<



  • Der Grund defür, dass Du const setzen musst, liegt in der Definition der = Operators des Iterators. Schriebst Du einfach nur cout << a; , dann funktioniert auch ein <<Operator, der keine const Referenz erwartet. Bei copy wird aber für jedes Element zwischen erstem und zweitem Argument drittes Argument = Element aufgerufen. Das dritte Argument ist dein ostream_iterator. Wenn Du hier mal guckst, wie der =operator definiert ist siehst Du

    ostream_iterator& operator= (const T& value);
    

    Der ostream_iterator ruft in diesem Operator den <<operator auf und zwar mit genau dieser konstanten Referenz. Also MUSST Du einen <<operator bereitstellen, der eine konstante Referenz entgegen nimmt.

    Auf der anderen Seite ist es aber sowieso eine gute Idee das Argument const zu machen, aber das haben die anderen ja shcon erklärt.


Anmelden zum Antworten