|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 03.01.2008, 22:12 Titel: Problem beim Löschen aus Vector |
|
|
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 |
|
|
Deviloper Junior JLI'ler
Anmeldedatum: 31.05.2006 Beiträge: 77
Medaillen: Keine
|
Verfasst am: 04.01.2008, 12:15 Titel: |
|
|
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? |
|
Nach oben |
|
|
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 04.01.2008, 18:24 Titel: |
|
|
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 _________________ Kein Rückzug! Kein Aufgeben! |
|
Nach oben |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 05.01.2008, 15:10 Titel: |
|
|
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]
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 |
|
|
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 06.01.2008, 10:36 Titel: |
|
|
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 _________________ Kein Rückzug! Kein Aufgeben! |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 06.01.2008, 16:01 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 06.01.2008, 16:22 Titel: |
|
|
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 |
|
|
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 06.01.2008, 18:44 Titel: |
|
|
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
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 07.01.2008, 15:29 Titel: |
|
|
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 |
|
|
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 07.01.2008, 15:45 Titel: |
|
|
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 |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 07.01.2008, 16:00 Titel: |
|
|
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 |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 07.01.2008, 18:01 Titel: |
|
|
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 |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 07.01.2008, 18:08 Titel: |
|
|
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 |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 07.01.2008, 21:49 Titel: |
|
|
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 |
|
|
LeeDiGer Super JLI'ler
Anmeldedatum: 31.08.2003 Beiträge: 366 Wohnort: Duisburg Medaillen: Keine
|
Verfasst am: 07.01.2008, 22:22 Titel: |
|
|
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ß
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 |
|
|
|
|
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
|