vector<*object> aus dem Speicher löschen=>Speicherverletzung
-
Kannst du ein minimales, aber vollständiges Beispiel posten, in dem dein Fehler immer noch auftritt?
Gibt es überhaupt einen Grund, wieso du nicht
std::vector<ant>(also ohne Zeiger) verwendest?
-
Minimalbsp. wird schwierig, da das ganze eine GUI Anwendung ist und daher recht verstrickt ist.
Ein Zugriff erfolgt zum Beispiel auf die Art und Weise:for(unsigned int i=0; i<vAnts.size(); i++) { vAnts[i]->drawTheAnt(dc); }Hier ein anderer Zugriff, zuerst vector auslesen, dann leeren und dann neu befüllen.
int maxFullness=0, currentFullness; double bestWeight[NUMBER_OUTPUT][SEIGHT_LENGTH*SEIGHT_HEIGHT]; for(int i; 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));//müsste evtl. nur einmal passieren! } } for(int i=0;i<vAnts.size();i++) { delete vAnts[i]; } vAnts.clear(); for(unsigned int i=0; i<NUMBER_ANTS; i++) { vAnts.push_back(new ant((double**)bestWeight)); }vector<ant*> deshalb, weil ich die ant's während der Laufzeit manchmal rauslösche und neu befüllen möchte. Also brauch ich new, und der gibt mir einen Zeiger auf die erzeugte Instanz zurück, daher ant*.
-
Glutamat schrieb:
vector<ant*> deshalb, weil ich die ant's während der Laufzeit manchmal rauslösche und neu befüllen möchte. Also brauch ich new, und der gibt mir einen Zeiger auf die erzeugte Instanz zurück, daher ant*.
Das geht auch auf dem "normalen" Weg.
-
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
intund manchmalunsigned 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_castdeutlich!
-
Und auch wenn man für Zugriffe keine Iteratoren nutzt, so nutze man
std::size_t(stattintoder ähnliches).
-
EOutOfResources schrieb:
Und auch wenn man für Zugriffe keine Iteratoren nutzt, so nutze man
std::size_t(stattintoder ä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::vectormit seinem Standard-Allokator bezieht seinen Speicher auch von Heap (also mitnewunddelete).
-
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...