JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=70e1ffba99a21f97c84f9ecf1d96b9d2Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Problem beim Löschen aus Vector
Gehe zu Seite 1, 2, 3  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 03.01.2008, 22:12    Titel: Problem beim Löschen aus Vector Antworten mit Zitat

Hat jemand mal in seinem Projekt diese Vector-Liste benutzt?
Ich habe einen Vector für 3D-Objekte implementiert, damit ich sie wegen dem Alphablending und Z-Buffer konflikt mit sort() sortieren kann.

Ich habe festgestellt, dass wenn ich ganz viele Objekte in kurzer Zeit erstelle (z.B. viele Schüsse in Form von Billboards) abfeuere, dann bleiben manchmal einige Rückstände beim Löschen der Schüsse übrig.

Wenn ich die Iterationsschleife für das Löschen durchlaufe, dann kann ich ganz normal nur auf aktive Objekte zugreifen. Wenn ich jedoch die mit size() die Größe des Vectors abrufe, denn merke ich, dass die größer als Null ist, obwohl, alle schüsse aus dem vector vermeintlich gelöscht wurden.


Hier ein Auschnitt aus dem Quellcode mit dem Löschvorgang:
Deklaration
Code:
      //Billboardliste
      vector<m_SObjects2D*>::iterator itObjects2D; //Iterator der Billboardliste
      vector<m_SObjects2D*> itListObjects2D; //Liste der Billboards

      //Sortierungstemplate für die Billboardobjekte
      template < class TEMPLATE_BEZEICHNER >
      class Vergleich
      {
      public:
      Vergleich() {}
         operator() (const TEMPLATE_BEZEICHNER& One, const TEMPLATE_BEZEICHNER& Two){
         return One->Billboard.m_fDistance > Two->Billboard.m_fDistance;
         }
      };

Löschvorgang
Code:
   //Billboards auf Löschung überprüfen
   itObjects2D = itListObjects2D.begin();
   while(itObjects2D != itListObjects2D.end())
   {
      switch((*itObjects2D)->iType)
      {
         case 1: //Schüsse
               if((*itObjects2D)->Billboard.m_fDistance > 50)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
                  continue;
               }
               break;
         case 2: //Raketen
               if((*itObjects2D)->Billboard.m_fDistance > 50)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
                  continue;
               }
               break;
         case 3: //Rauchschwaden
               if((*itObjects2D)->Billboard.m_bAnimationEnd)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
                  continue;
               }
               break;
         case 5: //Raketen des Gegners
               if((*itObjects2D)->Billboard.m_fDistance <= 1.0f)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
                  continue;
               }
               break;
         break;
      }
      ++itObjects2D;
   }

_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 04.01.2008, 12:15    Titel: Antworten mit Zitat

Hmm sieht eigtl. richtig aus ...

Deine Klasse Vergleich könntest du besser als struct anlegen (denke mal sie soll als functor dienen?), da dort default-access ja bekanntlich auf public anstatt auf private ist (sonst sind class und struct identisch).
CPP:
template<typename T>
struct compare_object
{
   bool operator()(T const & lhs, T const & rhs) const
   { return lhs->Billboard.m_fDistance > rhs->Billboard.m_fDistance; }
};




CPP:
vector<m_SObjects2D*>::iterator it(itListObjects2D.begin());

while (it != itListObjects2D.end())
{
   switch ((*it)->iType)
   {
      case 1: //Schüsse
         {
            if ((*it)->Billboard.m_fDistance > 50)
            {
               delete (*it);
               it = itListObjects2D.erase(it);
            }
         } break;
      case 2: //Raketen
         {
            if ((*it)->Billboard.m_fDistance > 50)
            {
               delete (*it);
               it = itListObjects2D.erase(it);
            }
         } break;
      case 3: //Rauchschwaden
         {
            if((*itObjects2D)->Billboard.m_bAnimationEnd)
            {
               delete (*it);
               it = itListObjects2D.erase(it);
            }
         } break;
      case 5: //Raketen des Gegners
         {
            if ((*it)->Billboard.m_fDistance <= 1.0f)
            {
               delete (*it);
               it = itListObjects2D.erase(it);
            }
         } break;
      default:
         { delete (*it); ++it; } break;
   }
}
... so ist es evtl. etwas eleganter, aber dennoch sollte es auch anderes gehen ... hmm soll der Zeiger eigtl. nicht gelöscht werden, wenn es keiner von deinen Typen ist? Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 04.01.2008, 18:24    Titel: Antworten mit Zitat

Code:
   default:
         { delete (*it); ++it; } break;

Das ist keine gute Idee. Die Objekte sollen ja nicht willkürlich gelöscht werden, wenn kein Casebefehl eingetreten ist. Die schleife hängt mit der Methode außerdem.
Bisher sah es für mich tatsächlich so aus, als wurde im RAM genau der Speicher belegt bleibt, den der Vector irgendwie nicht freigeben wollte.

Wie gesagt: die Fehler passieren nur, wenn ich in sehr schneller Abfolge neue Elemente erzeuge.

Das interessante ist, dass ab und zu ein teil der überbleibsel dann doch wieder freigegeben werden, wenn ich ganz viele Schüsse erstellt und dann wieder hab löschen lassen....ganz merkwürdig Wink
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 05.01.2008, 15:10    Titel: Antworten mit Zitat

Wann rufst du denn diese Schleife auf und was genau soll sie löschen?
Gibt es einen Grund dafür, dass es keine case-Marke für den Wert 4 gibt?

Gibt es einen Grund dafür, bei C++ Code immer noch die alten [code]-Tags zu benutzen? Nein, bitte in Zukunft [cpp] Wink

Falls alles nicht weiterhilft, geh mal mit dem Debugger durch, dadurch kannst du schon viele Fehlerquellen ausschließen/eingrenzen.
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 06.01.2008, 10:36    Titel: Antworten mit Zitat

Zitat:
Gibt es einen Grund dafür, dass es keine case-Marke für den Wert 4 gibt?

Ja, der Fall 4 ist reserviert, aber noch nicht implementiert.

Die Schleife wird in jedem Frame immer genau nach dem Rendervorgang der Scene ausgeführt. Dabei soll in diesem Beispiel überprüft werden, ob die Schüsse, Raketen etc. gelöscht werden sollen, weil sie entweder eine Kollision erlitten haben oder ihre maximalreichweite erreicht haben. Die If-Bedingungen hier sollte hier jetzt keiner so ernst nehmen. Die dienen erstmal nur zu Textzwecken und Vereinfachung. Aber im Prinzip soll diese Schleife das tun, was ich vorhin erklärt habe.

Ok, ich kann versuchen, es mit Debug zu analysieren. Wobei das das ziemlich lange dauern, weil ich einige hundertmale auf F5 drücken müsste, denn ich will ja ne Löschung für ganz viele Objekte auf Stabilität messen Wink
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 06.01.2008, 16:01    Titel: Antworten mit Zitat

wieso inkrementierst du den iterator in [default] anstatt sein Element durch erase zu entfernen? So rufst du doch öfter delete auf als vorgesehen. Das noch reste übrig sind, kann daran liegen, da delete (neben Speicherfregeben) nur den Destruktor des Objekts aufruft, es aber nicht entfernt. Je nachdem was du im Destruktor löschst bewirt das.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 06.01.2008, 16:22    Titel: Antworten mit Zitat

Hmm...was mir jetzt grad auffällt: Was soll das letzte break bewirken?

LeeDiGer hat Folgendes geschrieben:
CPP:
   //Billboards auf Löschung überprüfen
   itObjects2D = itListObjects2D.begin();
   while(itObjects2D != itListObjects2D.end())
   {
      switch((*itObjects2D)->iType)
      {
         case 1: //Schüsse
               if((*itObjects2D)->Billboard.m_fDistance > 50)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
                  continue;
               }
               break;
               //[...]
         break;
      }
      ++itObjects2D;
   }


Dann sollte es klar sein, wieso das ganze Zeug erst nach ner Menge Aufrufen gelöscht wird (und wieso du im Debug auch nicht mehr als einen Schleifendurchlauf erreichen dürftest).
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 06.01.2008, 18:44    Titel: Antworten mit Zitat

Da hast du etwas missverstanden. Gelöscht, wird normalerweise immer. Nur wenn ich z.B. in 1000 Frames hintereinander z.B. jeweils 2 neue Objekte (Schüsse) erstelle, dann zeigt der Vector noch ne Größe von einigen 100 Objekten. Wenn ich aber Alle Objekte des Vectors durchgehe und alle Objekte zählen möchte, dann stell ich fest, dass alle angeblich gelöscht sind.

Dieses "break" ist da schon richtig. du kannst auch hinschreiben "default: break;"
Wobei man dieses break anscheinend auch weglassen kann, merk ich grad...funktioniert genauso Question

DirectXer hat Folgendes geschrieben:
wieso inkrementierst du den iterator in [default] anstatt sein Element durch erase zu entfernen? So rufst du doch öfter delete auf als vorgesehen. Das noch reste übrig sind, kann daran liegen, da delete (neben Speicherfregeben) nur den Destruktor des Objekts aufruft, es aber nicht entfernt. Je nachdem was du im Destruktor löschst bewirt das.

Meinst du das hier?
Code:
 default:
         { delete (*it); ++it; } break;

Das war nicht meine Idee. Ich hab für den default-case nicht mehr als ein "break".

Wenn noch Speicherreste übrig bleiben sollen....wie erklärst du dir dann, dass der Vector noch Elemente zählt?? Eigentlich müsste die Vectorgröße ja 0 sein (also derselbe Effekt wie blindes löschen mit "clear()" ohne Speicherfreigaben).
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 15:29    Titel: Antworten mit Zitat

also das alleinige break; ist nicht nötig, du kannst in c++ auch gar kein default case wählen, das geht automatisch.

Außerdem kannst du case1 und 2 zusammenfassen, wenn dasselbe getan wird mit
CPP:
switch()
{
     case 1:
     case 2:
          .....
}


tu außerdem mal das continue in den switches raus und das ++itObjects2D allein in den default-Zweig.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 15:45    Titel: Antworten mit Zitat

Zitat:
tu außerdem mal das continue in den switches raus und das ++itObjects2D allein in den default-Zweig.

Wenn ich das tue, dann bleibt die Schleife hängen.

Wenn ich nur die continues rausnehme und ++itObjects2D da stehen lass wo es war, dann gehts erstmal, nur wenn dann ein objekt gelöscht werden soll, dann gibbet nen zugriffsfehler. Daher hab ich dieses continue eingebaut, damit es stabil läuft.

Und dass man die beiden ersten cases zusammenfassen kann, da geb ich dir völlig Recht. Aber das ist ja alles nur ein Test und soll erstmal getrennt bleiben. Vielleicht erweitere ich die Bedingungen noch.
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 16:00    Titel: Antworten mit Zitat

Also ich weiß nicht genau, wo der Fehler ist, aber ich benutze immer folgendes Konstrukt, das bei mir seit jeher zuverlässig und tadellos funktioniert:
http://www.jliforum.de/board/viewtopic.php?t=2519
Bei deinem Problem, wo der Fehler schwer zu finden ist, könnte es sich durchaus lohnen, alles noch einmal neu zu schreiben (ist ja nur eine Schleife). Und wenn du dann noch eine for statt eine while Schleife nimmst, ist die Struktur ja leicht anders und daher ist es evtl. unwahrscheinlicher, dass du alte Fehler übernimmst.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
The Lord of Programming
Living Legend


Alter: 37
Anmeldedatum: 14.03.2003
Beiträge: 3122

Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 18:01    Titel: Antworten mit Zitat

Lass dir doch mal nen Log ausgeben, bei dem du nachschauen kannst, was alles gelöscht wurde und was hinterher noch übrig ist.
Um das oder "richtiges" debuggen kommt man da oft nicht herum.

Wo bleibt die Schleife hängen? Was gibts für eine Zugriffsverletzung und warum?
_________________
www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console


Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet...
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 18:08    Titel: Antworten mit Zitat

Jona: das bezieht sich auf eine list, bei vector ist das so nicht nötig.

LeeDiGer: probiere mal dieses Konstrukt und sag mir was passiert:
CPP:
while(itObjects2D != itListObjects2D.end())
   {
      switch((*itObjects2D)->iType)
      {
         case 1: //Schüsse
               if((*itObjects2D)->Billboard.m_fDistance > 50)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
               }
               break;

         case 2: //Raketen
               if((*itObjects2D)->Billboard.m_fDistance > 50)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
               }
               break;

         case 3: //Rauchschwaden
               if((*itObjects2D)->Billboard.m_bAnimationEnd)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
               }
               break;

         case 5: //Raketen des Gegners
               if((*itObjects2D)->Billboard.m_fDistance <= 1.0f)
               {
                  delete (*itObjects2D);
                  itObjects2D = itListObjects2D.erase(itObjects2D);
               }
               break;
   
         default:
               ++itObjects2D;
               break;
      }
   }

das problem bei deiner Schleife ist, dass durch das ++itObjects2D der Iterator inkermentiert wird, egal was passiert. Außerdem kann das continue die switch und die while durcheinanderbringen, da break für beide definiert ist und continue/break ein paar sind; sie beziehen sich immer auf das lokalste (innerste) Produkt.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 21:49    Titel: Antworten mit Zitat

DirectXer hat Folgendes geschrieben:
Jona: das bezieht sich auf eine list, bei vector ist das so nicht nötig.

Also meines Wissens nach, sind Iteratoren darauf ausgelegt, überall mit gleich zu funktionieren. Also sollte das so auch mit einem Vector funktionieren. Einen Versuch wär es auf jedenfall Wert.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 07.01.2008, 22:22    Titel: Antworten mit Zitat

Jonathan_Klein hat Folgendes geschrieben:
Also ich weiß nicht genau, wo der Fehler ist, aber ich benutze immer folgendes Konstrukt

Das ist ein Konstrukt für eine "List" und ich hab nen Vector wegen Sortierung der Billboards wegen Alphablendingproblem. Kein Plan obs da besser wär...man kann da glaub ich auch gar nicht sie "Size" abrufen...was man dann nicht weiß, macht einen nicht heiß Wink


DirectXer hat Folgendes geschrieben:
das problem bei deiner Schleife ist, dass durch das ++itObjects2D der Iterator inkermentiert wird, egal was passiert

Wenn nicht immer der Iterator hochgezählt wird bei jedem Durchgang, dann bleibt die schleife hängen (man bedenke: es ist eine Whileschleife, wo ein Iterator ja im Schleifen-Block selbst iteriert werden soll)
Dein Vorschlag war leider nicht die Lösung.[/quote]
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Gehe zu Seite 1, 2, 3  Weiter
Seite 1 von 3

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum