Vector bestehend aus Pointer auf Objekte ausgeben



  • Hallo,

    ich habe einen Vector, der Pointer zu Filmen beinhaltet. Ich möchte nun die Attribute der einzelnen Filme ausgeben. Ich weiß aber nicht, wie ich auf diese Attribute zugreifen kann. Zuvor hatte mein Vector die Objekte selbst enthalten, da funktionierte das Ausgeben der Attribute mit folgenden Methoden.

    void Database::listVideos(){
    
        int counter=1;
        for(Mediafile* i : allMovies){
            cout << counter << "." <<endl;
            i->showMovie();
            cout <<endl;
            counter++;
        }
    
        cout <<endl;
    }
    
    void Mediafile::showMovie(){
    
        cout << "Titel: "<< getTitle() << endl
             << "Laenge: "<<  getLength() <<endl
             << "Bewertungen: " ;
        for (int i: Rating) {
            cout << i << " ";
        };
    
        cout << endl;
    
        cout <<"Durschnittliche Bewertung: " << getAverageRating()<<endl
             <<"Genre: "<< getGenre()<<endl;
    
    
    }
    

    Ich habe die Methoden durch den Debugger laufen lassen und herausgefunden, dass es zu ein Segmantation fault/SIGSEV bei getTitle() kommt. Habt ihr irgendwelche Ideen? Was muss ich verändern vielleicht meinen Getter?



  • Der Pointer im Vector wird dann wohl kaputt sein. Schuss ins Blaue: du fügst Adressen lokaler Variablen ein.



  • @manni66 sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    Der Pointer im Vector wird dann wohl kaputt sein. Schuss ins Blaue: du fügst Adressen lokaler Variablen ein.

    Das würde ich auch vermuten.

    @FirebladeRR, wo sollen denn die Mediafile-Objekte letzendlich gespeichert werden? Eine Database hört sich so an, als sei das ein guter Ort dafür. Gibt es einen guten Grund, dass Database::allMovies vermutlich ein std::vector<Mediafile*> ist, anstatt eines std::vector<Mediafile>?

    std::vector<Mediafile> sollte eigentlich intuitiv der erste Gedanke sein - irgendwie habe ich das Gefühl, dass Anfänger dennoch recht oft bei Pointern landen. Das ist nicht nur schwieriger zu handhaben, sondern auch noch fehleranfälliger und vor allem auch meist weniger effizient (Performance). Ich vermute das ist mal wieder die Schuld des Lehrmaterials 😉



  • Die Aufgabenstellung besagt, dass wir "im Vektor der Datenbank nur Pointer auf die einzelnen Mediafiles halten sollen, nicht die Objekte selbst". Was genau ist gemeint mit der Pointer ist kaputt, du fügst Adressen lokaler Variablen ein? Wie kann ich das Problem umgehen und mein Programm doch zum laufen bringen?



  • @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    nicht die Objekte selbst

    Und wo sind die Objekte?

    @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    Wie kann ich das Problem umgehen und mein Programm doch zum laufen bringen?

    Das kann dir niemand sagen, solange du nicht den Code zeigst, der den Vector befüllt.



  • Das kann ich gerne machen, der Vector wird aus einer txt Datei befüllt die Methode sieht wie folgt aus:

    void Database::init(){
    
        ifstream myfile;
        string line;
        string filename;
        int counter = 0;
        char xrating;
        int number = 0;
        int xlength = 0;
    
        while(counter<3){
            cout << "Geben Sie einen Dateipfad ein." << endl;
            getline(cin, filename);
    
            myfile.open(filename, ios::in);
            if(myfile.fail()){
                counter++;
            } else {
                counter+=4;
            }
        }
    
    
        if(counter==3){
            myfile.open("database.txt", ios::in);
            while (!myfile.eof()) {
                getline(myfile, line);
    
                if(line.at(0) == '*'){                              //(1)
                    xlength = myfile.tellg();
                }
    
                if(line.at(0) == 'T' && line.at(1) == 'i' && line.at(2) == 't' && line.at(3) == 'e' && line.at(4) == 'l' && line.at(5) == ':'){   //(2)
    
                    myfile.seekg(xlength ,ios_base::beg);          //(3)
                    Mediafile Object;
    
                    myfile.ignore(256, ' ');
                    getline(myfile, line);
                    Object.setTitle(line);                         //Titel wird erfasst
    
                    myfile.ignore(256, ' ');
                    getline(myfile, line);
                    Object.setLength(stoi(line));                  //Länge
    
                    myfile.ignore(256, ' ');
                    xrating = myfile.get();
                    while (xrating > 47 && xrating < 58) {
    
                        number = (int)xrating-48;
                        Object.addRating(number);
                        myfile.ignore(256, ' ');
                        xrating = myfile.get();                    //Bewertungen
    
                    }
    
                    getline(myfile, line);
                    line = xrating + line;
                    Object.setGenre(line);                         //Genre
    
                    addMovies(Object);                             //(4)
    
                }
            }
        } else {
            myfile.close();
            myfile.open(filename, ios::in);
            while (!myfile.eof()) {
                getline(myfile, line);
    
                if(line.at(0) == '*'){                              //(1)
                    xlength = myfile.tellg();
                }
    
                if(line.at(0) == 'T' && line.at(1) == 'i' && line.at(2) == 't' && line.at(3) == 'e' && line.at(4) == 'l' && line.at(5) == ':'){   //(2)
    
                    myfile.seekg(xlength ,ios_base::beg);          //(3)
                    Mediafile Object;
    
                    myfile.ignore(256, ' ');
                    getline(myfile, line);
                    Object.setTitle(line);                         //Titel wird erfasst
    
                    myfile.ignore(256, ' ');
                    getline(myfile, line);
                    Object.setLength(stoi(line));                  //Länge
    
                    myfile.ignore(256, ' ');
                    xrating = myfile.get();
                    while (xrating > 47 && xrating < 58) {
    
                        number = (int)xrating-48;
                        Object.addRating(number);
                        myfile.ignore(256, ' ');
                        xrating = myfile.get();                    //Bewertungen
    
                    }
    
                    getline(myfile, line);
                    line = xrating + line;
                    Object.setGenre(line);                         //Genre
    
                    addMovies(Object);                             //(4)
    
                }
            }
        }
        myfile.close();
        cout << allMovies.size() << endl;
    }
    

    ich weiß, dass init nicht ideal gelöst ist. Ich werde mich nachdem ich die anderen Aufgaben bewältigt habe wieder dran setzen und was meinst du mit wo sind die Objekte?



  • Nun solltest du noch die addMovies Funktion zeigen. Bei der wird wohl der Haken liegen.



  • if(…) {
        Mediafile Object;
    …
    }
    

    Das ist ein lokales Objekt. Nach } existiert es nicht mehr. Ein Pointer darauf ist ungültig. Dereferenzieren führt zu deinem Fehler.

    Leider zeigst du immer noch nicht den Code, der etwas in den Vector einfügt.

    @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    was meinst du mit wo sind die Objekte?

    Irgendwo müssen die Objekte ja im Speicher liegen, solange du darauf zeigst. Vermutlich tun sie das eben nicht, was dein Fehler ist.



  • Wie hast du denn addMovies(...) implementiert?

    Ändere mal deinen Code entsprechend dem Hinweis von @Finnegan, also benutze std::vector<Mediafile> (keine Zeiger).

    PS: Fast jede Zeile deines Code ist verbesserungsfähig:

    • Warum hast du denn fast identischen Code in den if(counter==3) { ... } else { ... }-Anweisungsblöcken???
    • Warum die komplizierte Abfrage auf "Titel:"?
    • Warum benutzt du ASCII-Codes anstatt Zeichen ('0'...'9')?
    • Und deine Leseschleife mit eof ist auch falsch.

    Womit lernst du denn C++?



  • @Th69 Womit lernst du denn C++?-> inverted classrooms 🙂

    addMovies sieht wie folgt aus

    void Database::addMovies(Mediafile xMovie){
    
        Mediafile* pMovie = &xMovie;;
        allMovies.push_back(pMovie);
    
    
    }
    


  • @FirebladeRR der Parameter ist eine Kopie des Objektes und ebenfalls eine lokale Variable. Am Ende der Funktion ist der Zeiger ungültig.

    Was sagt die Aufgabenstellung dazu, wo das Objekt liegen soll? Heap? Dann muss irgendwo ein new vorkommen.



  • @manni66 Ok und wie kann ich das umgehen?



  • Also in der Aufgabenstellung steht sogar, dass wir in unseren Methoden lokale Objekte per new zu erzeugen, da ansonsten die Sichtbarkeit der Objekte nur bis zum Methodenende reicht, aber wenn ich in addMovies new verwende bringt mich das auch nicht weiter. Ich kriege trotzdem den selben Fehler

    void Database::addMovies(Mediafile xMovie){
    
        Mediafile* pMovie = new Mediafile;
                pMovie= &xMovie;
        allMovies.push_back(pMovie);
    
    
    }
    

    Ich habe es hiermit auch versucht und trotzdem der selbe Fehler. Setze ich vielleicht new an der falschen Stellen an?



  • @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    Mediafile* pMovie = new Mediafile;

    Ein neues Objekt wird angelegt, die Adresse steht in pMovie.

    @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    pMovie= &xMovie;

    Die Adresse wird vergessen und stattdessen wieder die Adresse eines lokalen Objektes hinterlegt.

    Vielleicht funktioniert

    
    void Database::addMovies(Mediafile xMovie){
        allMovies.push_back(new Mediafile(xMovie));
    }
    
    

    Schlauer wäre es natürlich, schon beim Einlesen ein Objekt mit new zu erzeugen und den Zeiger darauf in den Vector einzufügen.

    OT: leider ist dein Lehrer völlig inkompetent. Du lernst absoluten Schrott. Die Objekte in den Vector zu packen wäre der richtige Weg gewesen.



  • @manni66 ich kann dir nicht sagen wie dankbar ich dir gerade bin ❤
    ich sitze schon zwei Tage dran und es funktioniert nun mit deinen zwei Zeilen Code 😂
    auch vielen Dank an alle anderen.



  • @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    void Database::addMovies(Mediafile xMovie){
    
        Mediafile* pMovie = new Mediafile;
                pMovie= &xMovie;
        allMovies.push_back(pMovie);
    
    
    }
    

    Ich habe es hiermit auch versucht und trotzdem der selbe Fehler. Setze ich vielleicht new an der falschen Stellen an?

    Nicht das new, sondern den &-Operator. Du setzt hier pMovie direkt wieder auf die Adresse der lokalen Variablen xMoive - das ist die, die ungültig ist, sobald diese Funktion verlassen wurde. Nimm diese Zeile heraus:

                pMovie= &xMovie;
    

    ... dann werden auch die ganzen anderen Probleme sichtbar, die darunter vergraben liegen. Z.B.:

    • new Mediafile erzeugt lediglich eine neue, default-kostruierte Mediafile-Instanz, ohne die ganzen Daten, die du vorher gesetzt hast. Du solltest die übergebene xMovie-Instanz natürlich kopieren - z.B. mit Mediafile* pMovie = new Mediafile{ xMovie }.
    • zu jedem new gehört auch ein delete an einer passenden Stelle, sonst gibts Speicherlecks. Da braucht es also noch Aufräum-Code, der steht üblicherweise im Destruktor der besitzenden Klasse (hier Database). Eleganter ginge das natürlich mit einem std::vector<std::unique_ptr<Mediafile>>.
    • wenn deine Database selbst Ressourcen verwaltet, wie in diesem Fall Speicherressourcen, dann musst du auch noch mindestens einen Copy Constructor (Database::Database(const Database&)) und einen Copy Assignment Operator (Database::operator=(const Database&)) implementieren, der die verwalteten Ressourcen korrekt handhabt. Ansonsten kommt man in Teufelsküche, wenn man unbedarft mit Database-Objekten hantiert (Rule of Three/Rule of Five).

    Ich schrieb ja weiter oben, dass das mit den Pointern "schwieriger zu handhaben und fehleranfälliger" ist. Das beste wäre natürlich, gleich einen std::vector<Mediafile> zu nehmen. Da hat man solche Probleme nicht und es läuft wahrscheinlich auch noch effizienter.



  • @FirebladeRR sagte in Vector bestehend aus Pointer auf Objekte ausgeben:

    @manni66 ich kann dir nicht sagen wie dankbar ich dir gerade bin ❤
    ich sitze schon zwei Tage dran und es funktioniert nun mit deinen zwei Zeilen Code 😂
    auch vielen Dank an alle anderen.

    Glaub nicht, dass es das schon war. Die eigentlichen Probleme fangen gerade erst an ... es sei denn natürlich, man ist auch mit fehlerhaftem Code zufrieden, der "irgendwie läuft" und einem sofort um die Ohren fliegt, sobald man ihn nur schief anguckt.


Log in to reply