[c++] Problem mit Iterator bei Anwendung der Funktion erase() auf container vector

Mizi Mace

Mitglied
einen wunderschönen guten tag,

folgende funktion soll aus einen vector p, der elemente der klasse individual beinhaltet, elemente der anzahl size auswählen und in einen neuen vector i speichern. damit keine elemente doppelt ausgewählt werden können, werden diese aus dem vector gelöscht. dies geschieht mit einen iterator it und der funktion erase() und genau dort ist das problem. im iterator wird das richtige element hinterlegt, beim aufruf der funktion p.erase(it) stürzt das programm ab. beim compilieren konnte kein fehler gefunden werden.

hier die funktion:

C++:
vector<individual> selectionParetoWtkfDel(vector<individual> p, int size) {
    const int ANZCONTESTANTS = 5;               
    int z;                                                                    
    int bestIndex;                                                              
    float bestRang;                                                             
    vector<individual> e;                                                   
    vector<individual>::iterator it;

    e.reserve(size);
    // Bilden des neuen Vectors
    for(int i=size; i<size; i++) {
        bestIndex = 0;                                                          
        bestRang = 100000;
        // Auswahl des Elements
        for(int j=0; j<ANZCONTESTANTS; j++) {
            z = rand()%a.size();                                               
            if(p[z].get_rang() < bestRang) {                                  
                bestIndex = z;                                                  
                bestRang = p[z].get_rang();                                    
            }
        }
        e.push_back(p[bestIndex]);
        it = p.begin()+bestIndex; // Klappt noch, mit richtigen Element
        p.erase(it); // Klappt nicht, führt zu Absturz, kein Compilierfehler
    }
    return e;                                                                   
}

hier noch die klasse individual:

C++:
class individual : public arguments, public values, public fitness {            // Klasse für Lösungskandidat
    public:
        individual(const individual &indi);                                     // Copy-Konstruktor für Klasse individual
        individual(string *initAtt,                                             // Konstruktor für Klasse individual
                   string *initArg,
                   string *initCon,
                   string *initVal,
                   string &initFit);
        ~individual();                                                          // Destruktor für Klasse individual
        void valuation(void);                                                   // Bewertung des Lösungskandidaten
        void print(void);                                                       // Ausgabe auf Bildschrim
        void print(string file);                                                // Ausgabe in Datei
};

und die mutter-klasse fitness mit der verwendeten funktion get_rang():

C++:
class fitness {                                                                 // Klasse für Fitnesswerte
    protected:
        int anzFit;                                                             // Anzahl der zu optimierenden Ziele (im Sinne des Optimierungsproblems)
        float* fit;                                                             // Fitnessvektor
        float* sharing;                                                         // Sharingwert
        int  rang;                                                              // Rang
        void set_fitness(values &val);                                          // Funktion zur Berechnung der Fitness
    public:
        fitness(const fitness &f);                                              // Copy-Konstruktor für Fitness
        fitness(string &initFit);                                               // Konstruktor für die Klasse fitness
        ~fitness();                                                             // Destruktor für die Klasse fitness
        int get_anzFitness(void) { return anzFit; }                             // Funktion zum Abrufen der Anzahl der Fitnesskriterien
        float get_fitness(int index) const { return fit[index]; }               // Funktion zum Abrufen der Fitness
        float get_sharing(int index) { return sharing[index]; }                 // Funktion zum Abrufen des Sharingswerts
        int get_rang(void) const { return rang; }                               // Funktion zum Abrufen des Rangs
        void set_fitness(int index, float fitn) {fit[index] = fitn; }           // Funktion zum Speichern der Fitness
        void set_sharing(int index, float share) { sharing[index] = share; }    // Funktion zum Speichern des Sharingswerts
        void set_rang(int r) { rang = r; }                                      // Funktion zum Speichern des Rangs
};

gruss
mizi
 
Hi.

Bist du dir sicher, das das der richtige Code ist?

Eigentlich wird die Schleife for(int i=size; i<size; i++) { nie betreten...

Kannst du ansonsten mal ein Minimalbeispiel machen was man kompilieren kann.

Gruß
 
einen wunderschönen guten tag,

du hast natürlich recht. bei dem code wird die äußere schleife nie durchlaufen. es muss dort natürlich int i=0 stehen. das ist im originalcode auch so. da muss ich mir etwas beim übertragen vermehrt haben.

ich hab das problem mal reduziert:

main.cpp:
C++:
#include "individual.h"

int main(int argc, char *argv[]) {
    int sizeAll = 10;
    int sizeSection = 4;
    vector<individual> all;
    vector<individual> section;
    individual* ind;

    all.reserve(sizeAll);
    section.reserve(sizeSection);
    // Füllen des Vektors all
    for(int i=0; i<sizeAll; i++) {
        ind = new individual(i);
        all.push_back(*ind);
        delete ind;
    }
    // Ermitteln des Vektors section
    section = selectionParetoWtkfDel(all, sizeSection);
    // Ausgabe der Vektoren
    for(int i=0; i<sizeAll; i++) {
        cout << all[i].rang << "\t";
    }
    cout << "\n";
    for(int i=0; i< sizeSection; i++) {
        cout << section[i].rang << "\t";
    }
    cout << "\n";
}

individual.h
C++:
#ifndef individual_h
#define individual_h

#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;


class fitness {                                                                 // Klasse für Fitnesswerte
    public: // ehemals protected
        int  rang;                                                              // Rang
    public:
        fitness(const fitness &f);                                              // Copy-Konstruktor für Fitness
        fitness(int r);                                                         // Konstruktor für die Klasse fitness
        ~fitness();                                                             // Destruktor für die Klasse fitness
        int get_rang(void) const { return rang; }                               // Funktion zum Abrufen des Rangs
};

class individual : public fitness {                                             // Klasse für Lösungskandidat
    public:
        individual(const individual &indi);                                     // Copy-Konstruktor für Klasse individual
        individual(int r);                                                      // Konstruktor für Klasse individual
        ~individual();                                                          // Destruktor für Klasse individual
};


vector<individual> selectionParetoWtkfDel(vector<individual> p, int size);


#endif

individual.cpp
C++:
#include "individual.h"

// Copy-Konstruktor für Fitness
fitness::fitness(const fitness &f) {
    rang = f.rang;
}

// Konstruktor für die Klasse fitness
fitness::fitness(int r) {
    rang = r;
}

// Destruktor für die Klasse fitness
fitness::~fitness() {

}

// Copy-Konstruktor für Klasse individual
individual::individual(const individual &indi) : fitness(dynamic_cast<const fitness&>(indi)) {

}

// Konstruktor für Klasse individual
individual::individual(int r) : fitness(r) {

}

// Destruktor für Klasse individual
individual::~individual() {

}

// Bilden der Auswahl
vector<individual> selectionParetoWtkfDel(vector<individual> p, int size) {
    const int ANZCONTESTANTS = 5;
    int z;
    int bestIndex;
    float bestRang;
    vector<individual> e;
    vector<individual>::iterator it;

    e.reserve(size);
    // Bilden des neuen Vectors
    for(int i=0; i<size; i++) {
        bestIndex = 0;
        bestRang = 100000;
        // Auswahl des Elements
        for(int j=0; j<ANZCONTESTANTS; j++) {
            z = rand()%p.size();
            if(p[z].get_rang() < bestRang) {
                bestIndex = z;
                bestRang = p[z].get_rang();
            }
        }
        e.push_back(p[bestIndex]);
        it = p.begin()+bestIndex;
        p.erase(it);
    }
    return e;
}

die fast leeren klassen sehen jetzt natürlich etwas albern aus und für das problem völlig unsinnig. interessant ist, dass das ganze jetzt funktioniert, so wie ich mir das vorstelle bzw. interessant ist das nicht, sondern warum es im anderen beispiel nicht funktioniert. es liegt also nicht an dieser funktion, sondern in einer anderen ebene meines programms.

danke vielmals für den hinweis. ich werd eventuell schreiben, woran es denn nun wirklich hängt. vielleicht ist dies dann auch meine (tatsächliche) frage.

gruss
mizi
 
Ich geh mal davon aus, das es daran liegt, dass du zu viel mit Zeigern spielst ... weiß nicht ob du genug Erfahrung damit hast, und selbst dann wüsstest du das du es zu oft einsetzt ;)

Zeig mal c-tor, copy-c-tor, d-tor und assignment operator von indiviudual und fitness ...
 
einen wunderschönen guten tag,

in den konstruktoren für die klasse individual werden lediglich die parameter an die mutterklassen weitergegeben. im destruktor ist dann auch nichts zu tun.

copy-c-ctor für individuell
C++:
individual::individual(const individual &indi)
                    :arguments(dynamic_cast<const arguments&>(indi)),
                     values(dynamic_cast<const values&>(indi)),
                     fitness(dynamic_cast<const fitness&>(indi)) {
                                                                                // Nichts zu tun
}

c-tor für individuell
C++:
individual::individual(string *initAtt,
                       string *initArg,
                       string *initCon,
                       string *initVal,
                       string &initFit)
                    :arguments(initAtt, initArg),
                     values(initCon, initVal),
                     fitness(initFit) {
                                                                                // Nichts zu tun
}

d-tor für individuell
C++:
individual::~individual() {
                                                                                // Nichts zu tun
}

und die mutterklasse fitness:

copy-c-tor für fitness
C++:
fitness::fitness(const fitness &f) {
    anzFit = f.anzFit;                                                         
    rang = f.rang;                                                              
    fit = new float[anzFit];                                                 
    sharing = new float[anzFit];                                      
    for(int i=0; i<anzFit; i++) {                                          
        fit[i] = f.fit[i];                                              
        sharing[i] = f.sharing[i];                        
    }
}

c-tor für fitness
C++:
fitness::fitness(string &initFit) {
    istringstream issFit;                            

    issFit.str(initFit);                                    
    issFit >> anzFit;                                     
    rang = 0;                                                  
    fit = new float[anzFit];                             
    sharing = new float[anzFit];                  
    for(int i=0; i<anzFit; i++) {                      
        fit[i] = 0;                                                 
        sharing[i] = 1;                                      
    }
}

d-tor für fitness
C++:
fitness::~fitness() {
    delete[] fit;                          
    delete[] sharing;               
}

die string-variablen werden zuvor aus txt-dateien ausgelesen und erst im entsprechenen konstruktor auseinandergenommen.

gruss
mizi
 
Warum arbeitest du überhaupt mit rohen Arrays? (Hier wäre std::vector gut, schon allein weil die meisten Zeilen deines Codes rausfliegen würden und du das implementieren von copy-c-tor usw. dir sparen könntest ;) )
Und wo ist dein Zuweisungsoperator von fittness? Du hast die regel der G3 verletzt ;)
 
einen wunderschönen guten morgen,

die verwendung von "rohen arrays" ist natürlich zu überdenken. aber da sich mit dem zugriff auf die arrays nichts ändert, ist das erstmal nicht so wichtig. das lässt sich relativ problemlos ändern. ein copy-konstruktor wird deshalb eventuell nicht überflüssig (vielleicht aber doch). das müsste ich im gesamtzusammenhang überprüfen.

die regel drei besagt:
Eine abgeleitete Klasse ist für die Initialisierung ihrer Basisiklasse zuständig. Der Konstruktor der abgeleiteten Klasse reicht dazu alle erforderlichen Parameter an den Konstruktor der Basisklasse weiter. Auf eine explizite Initialisierung der Basisklasse kann nur verzichtet werden, wenn die Basisklasse keinen oder einen explizit erstellten parameterlosen Konstruktor hat.

genau das ist hier geschehen. oder kennst du eine andere regel? das würde mich natürlich intere

gruss
mizi
 
Einen wunderschönen guten Morgen,

Bitte halte dich an die Netiquette hier, und achte auf die Groß-/Kleinschreibung!

Ich erkenne nicht ganz, dass meine Frage gegen die Netiquette verstößt. Ich wollte lediglich nachfragen, ob sich die Regeln unterscheiden (was ja auch der Fall ist). Falls die Frage beleidigend aufgefasst wurde, möchte ich mich dafür entschuldigen. Groß- und Kleinschreibung sehe ich ein. Das ist eine Angewohnheit von mir. Ich werd mich versuchen daran zu halten.


Danke für die Links. Ich werd mir die erstmal durcharbeiten und meinen Code nach entsprechenden Unzulänglichkeiten überprüfen. Dies behebt dann vielleicht auch den Fehler.

Edit:
Ihr habt natürlich recht. Es fehlt die konkrete Definition des Zuweisung-Operator. Mein Programm kann schließlich nicht wissen, was es bei einer Zuweisung denn nun alles zuweisen soll. Vielen Dank.

Gruss
Mizi
 
Zuletzt bearbeitet:
Zurück