vector<*object> aus dem Speicher löschen=>Speicherverletzung



  • Du kannst auch einen normalen vector<> umbauen, wenn du seinen Inhalt ändern willst (Stichwort: insert()/erase()). Wenn du Angst vor dem dabei nötigen Umkopieren der Elemente hast, kannst du auch einen anderen Comtainer verwenden, z.B. std::list<>.
    Ansonsten kommt der SegFault womöglich daher, daß du irgendwo etwas dort reingepackt hast, was nicht per new angelegt wurde.



  • for(int i; i<vAnts.size(); i++)
    

    Nicht gut, schau dir das nochmals genau an.

    Warum manchmal int und manchmal unsigned int ? Warum keine Iteratoren?

    P.S.:

    memcpy(bestWeight,vAnts[i]->getBrain()->getWeight(),NUMBER_OUTPUT*SEIGHT_LENGTH*SEIGHT_HEIGHT*sizeof(double));
    

    Das geht sicher auch einfacher, z.B. mit std::copy() .

    vAnts.push_back(new ant((double**)bestWeight));
    

    Diesen Cast brauchst du auch kaum. Wenn doch (unwahrscheinlich), mach die Gewaltanwendung wenigstens mit reinterpret_cast deutlich!



  • Und auch wenn man für Zugriffe keine Iteratoren nutzt, so nutze man std::size_t (statt int oder ähnliches).



  • EOutOfResources schrieb:

    Und auch wenn man für Zugriffe keine Iteratoren nutzt, so nutze man std::size_t (statt int oder ähnliches).

    Wenn du mir so kommst, nein. Dann nimmt man std::vector<T>::size_type :p



  • Danke erstmal für eure AW!
    Werde die Tipps noch umsetzen, dachte aber vielleicht hilft der gesamte Code der Klasse weiter!? So groß ist sie ja eh nicht:

    HEADER

    class controller
    {
        public:
            controller();
            virtual ~controller();
            void drawTheSim(wxPaintDC *dc);
            void doTheSim();
            void start();
            bool isRunning();
        protected:
    
            std::vector<ant*> vAnts;
            std::vector<food*> vFood;
            int timeElapsed;
            bool simRunning;
        private:
    };
    

    SOURCE

    controller::controller()
    {
        //ctor
        srand(time(0));
    
        for(std::size_t i=0; i<NUMBER_ANTS; i++)
        {
            vAnts.push_back(new ant(0));
        }
    
        for(std::size_t i=0; i<NUMBER_FOOD; i++)
        {
            vFood.push_back(new food());
        }
    
        simRunning=false;
        timeElapsed=0;
    
    }
    
    controller::~controller()
    {
    
        for(std::size_t i=0;i<vAnts.size();i++)
        {
            delete vAnts[i];
        }
    
        for(std::size_t i=0;i<vFood.size();i++)
        {
            delete vFood[i];
        }
    
        vAnts.clear();
        vFood.clear();
    }
    
    void controller::doTheSim()
    {
        for(std::size_t i=0; i<vAnts.size(); i++)
        {
            vAnts[i]->moveOn(vFood);
        }
    
        if(timeElapsed>=playTime)
        {
            int maxFullness=0, currentFullness;
            double bestWeight[NUMBER_OUTPUT][SEIGHT_LENGTH*SEIGHT_HEIGHT];
    
            for(std::size_t i=0; i<vAnts.size(); i++)
            {
                currentFullness=vAnts[i]->getFullness();
                if(currentFullness>maxFullness)
                {
                    currentFullness=vAnts[i]->getFullness();
                    memcpy(bestWeight,vAnts[i]->getBrain()->getWeight(),NUMBER_OUTPUT*SEIGHT_LENGTH*SEIGHT_HEIGHT*sizeof(double));
    
                }
    
            }
    
            for(std::size_t i=0;i<vAnts.size();i++)
            {
               delete vAnts[i];
            }
            vAnts.clear();
    
            for(std::size_t i=0; i<NUMBER_ANTS; i++)
            {
                vAnts.push_back(new ant((double**)bestWeight));
            }
    
            simRunning=false;
            timeElapsed=0;
        }
    
        timeElapsed++;
    }
    
    void controller::drawTheSim(wxPaintDC *dc)
    {
        if(isRunning())
        {
            wxColor color;
    
            color.Set(250,170,70,255);
            dc->SetBrush(wxBrush(color));
            dc->DrawRectangle(0,0,PANEL_X+ANT_SPEED,PANEL_Y+ANT_SPEED);
    
            for(unsigned int i=0; i<vAnts.size(); i++)
            {
                vAnts[i]->drawTheAnt(dc);
            }
    
            for(unsigned int i=0; i<vFood.size(); i++)
            {
                vFood[i]->drawTheFood(dc);
            }
        }
        else
        {
            dc->DrawText( _("New Generation"), 0, 0);
        }
    
    }
    


  • Nexus hat dir das Problem schon gezeigt...



  • EOutOfResources schrieb:

    Nexus hat dir das Problem schon gezeigt...

    Auf Zeiger verzichten?
    Wie soll das gehen? Wie kann ich dynamisch den vector befüllen und entleeren mit ant Elementen, ohne auf new/delete zurückzugreifen?



  • Glutamat schrieb:

    EOutOfResources schrieb:

    Nexus hat dir das Problem schon gezeigt...

    Auf Zeiger verzichten?
    Wie soll das gehen? Wie kann ich dynamisch den vector befüllen und entleeren mit ant Elementen, ohne auf new/delete zurückzugreifen?

    statt
    vec.push_back(new ant(1));
    einfach
    vec.push_back(ant(1));
    schreiben?



  • Glutamat schrieb:

    Auf Zeiger verzichten?

    Nein, lies nochmals meinen Post.

    Wobei auf Zeiger und manuelle Speicherverwaltung verzichten sowieso eine gute Idee ist.



  • Falls du (Glutamat) es noch nicht gewusst hast: Ein std::vector mit seinem Standard-Allokator bezieht seinen Speicher auch von Heap (also mit new und delete ).



  • Falls du (Glutamat) es noch nicht gewusst hast: Ein std::vector mit seinem Standard-Allokator bezieht seinen Speicher auch von Heap (also mit new und delete).

    vAnts.push_back(ant(0));
    

    OK, wie funktioniert das nun im Detail? Eine Instanz einer Klasse wird erstellt mit ant(0). vector reserviert Speicher am Heap und macht eine 1:1 Kopie meiner Instanz. Richtig?



  • Nexus schrieb:

    Glutamat schrieb:

    Auf Zeiger verzichten?

    Nein, lies nochmals meinen Post.

    Wobei auf Zeiger und manuelle Speicherverwaltung verzichten sowieso eine gute Idee ist.

    Was meinst du damit? Das mit dem nicht initialisierten i in der for Schleife? Schon erledigt, das wars nicht.



  • Glutamat schrieb:

    OK, wie funktioniert das nun im Detail? Eine Instanz einer Klasse wird erstellt mit ant(0). vector reserviert Speicher am Heap und macht eine 1:1 Kopie meiner Instanz. Richtig?

    Ja, kommt hin. Wobei der Compiler eventuell(?) das Ganze noch soweit optimieren kann, daß der vector<> erst den Speicher reserviert und dann deine Instanz dort direkt erstellt.

    Edit: Und was ein großes Problem sein könnte, ist der Cast des Arrays in einen Doppelzeiger - so weit geht die Verwandschaft zwischen Zeigern und Array nicht, daß du dort etwas sinnvolles erwarten kannst.



  • Glutamat schrieb:

    EOutOfResources schrieb:

    Nexus hat dir das Problem schon gezeigt...

    Auf Zeiger verzichten?
    Wie soll das gehen? Wie kann ich dynamisch den vector befüllen und entleeren mit ant Elementen, ohne auf new/delete zurückzugreifen?

    oder machs mit einem pointer container, boost hat ptr_vector (oder so ähnlich)
    der löscht die objekte automatisch. oder nimm std::vector< std::shared_ptr<Ant> >



  • Wie sind denn ant und food deklariert? Sind da evtl. die großen 3 notwendig und implementiert?



  • Skym0sh0 schrieb:

    oder machs mit einem pointer container, boost hat ptr_vector (oder so ähnlich)
    der löscht die objekte automatisch. oder nimm std::vector< std::shared_ptr<Ant> >

    Nein, nimm wenn möglich Objekte. Die zusätzliche Indirektion ist normalerweise unnötig. Und der Overhead für Shared-Ownership erst recht...

    ptr_vector<T> kann man nehmen, falls man besitzende Zeiger braucht (z.B. nicht- bzw. teuer kopierbare oder polymorphe Objekte). vector<shared_ptr<T>> ist angebracht, falls die Objekte noch irgendwo ausserhalb referenziert werden, wo ebenfalls ein Besitzanspruch vorhanden ist. Das kommt aber eher selten vor...


Anmelden zum Antworten