2016-07-21 12 views
0

kann ich um Hilfe bitten, um zu bestätigen, ob mein Problem von einem Design-Problem kommt, oder wenn es würde eine mögliche saubere Lösung für die folgenden sein:„Vector Iteratoren unvereinbar“, wenn sie in einem Selbstversorger-Vektorschleife Löschen

Entity.h

class CLEntity3D 
{ 
public: 
    CLEntity3D(); 
    virtual ~CLEntity3D(); 
    virtual void update() = 0; 

    static std::vector<CLEntity3D*> vecEntity; 
}; 

Entity.cpp

int CLEntity3D::nbrEntity = 0; 
std::vector<CLEntity3D*> CLEntity3D::vecEntity; 

CLEntity3D::CLEntity3D() 
{ 
    vecEntity.push_back(this); 
} 
CLEntity3D::~CLEntity3D() 
{ 
    vecEntity.erase((std::remove(vecEntity.begin(), vecEntity.end(), this)), vecEntity.end());  
} 

verschiedene abgeleitete Klasse erstellen/löschen verschiedene Entitäten durch das Programm-Objekt, das alles funktioniert gut.

In einer Szene Klasse, ich habe die folgenden Methoden:

void CLScene::Update() 
{ 
    for (auto& iter : CLEntity3D::vecEntity) { 
     iter->update(); 
    } 
} 

void CLScene::ClearScene() 
{ 
    for (auto& iter : CLEntity3D::vecEntity) { 
     delete(iter); iter = nullptr; 
    } 
    CLEntity3D::vecEntity.clear(); 
} 

-Update ist in Ordnung, das Problem mit ClearScene ist(). Ich bekomme eine "Vector Iterators Inkompatible" Debug-Assertion.

Aus meiner Forschung scheint das allgemeine Problem zu sein, weil die Iteratoren von verschiedenen Vektoren sind, die ich glaube nicht, ist das Problem hier. Ich denke, das Problem ist, wenn ClearScene() aufgerufen wird, jedes delete (iter) ändert die Größe von vecEntity durch den CLEntity3D-Destruktor und macht daher den Iterator in der ClearScene-Schleife ungültig. Habe ich recht?

Meine Frage wäre dann: Gibt es eine Möglichkeit, alle Clentity3D-Objekte aus CLScene mit diesem Design zu löschen?

Ich glaube, ich könnte CLScene die vecEntity halten, die das Problem beseitigen würde, aber dies würde bedeuten, dass CLScene müssten alle Schöpfung/Löschen von Einheiten verwalten, also nicht so vielseitig sein ...

PS: Ich weiß, dass dieses Beispiel nicht zu kompilieren ist, aber da meine Frage mehr nach Konzept ist ... bitte rate mir, ob ich etwas anderes bereitstellen soll.

+2

Das Problem ist, dass in 'CLEntity3D', Sie' this' zum 'vecEntity' Vektor hinzuzufügen, aber die 'Clentity3D' -Instanz kann dynamisch aufgebaut sein oder auch nicht (zB' Clentity3D entity; 'vs.' Clentity3D * entity = new Clentity3D(); '). Wenn keine dynamische Zuweisung durchgeführt wurde, können Sie 'delete' nicht verwenden. – Holt

+0

Ich glaube, Sie wollten '* iter = nullptr;' anstelle von 'iter = nullptr;' schreiben, wenn Sie den Iterator so ändern, wie er zum nächsten gehen soll? – SHR

+0

@SHR Dies ist eine For-Range-Schleife, die iter-Variable ist eigentlich der Zeiger selbst, nicht der Iterator. – Holt

Antwort

1

Das Problem ist, Sie können nichts aus dem zugrunde liegenden Vektor entfernen, während in einem Bereich für Schleife basiert.

Die Schleife in Ihrer ClearScene Methode löscht CLEntity3D Instanzen, die in seinem Destruktor den gleichen Vektor ändert, den Sie in Ihrer for-Schleife verwendet haben.

Eine relativ einfache Lösung wäre Ihre ClearScene zu so etwas zu ändern:

void CLScene::ClearScene() 
{ 
    auto vectorCopy = CLEntity3D::vecEntity; 
    for (auto& iter : vectorCopy) { 
     delete iter; 
    } 
} 

Das funktioniert, weil die Schleife auf einer Kopie arbeitet, und das Entfernen geschieht auf dem Original.

Beachten Sie, dass der ursprüngliche Vektor nach der Schleife nicht gelöscht werden muss, da die Destruktoren sicherstellen, dass der Vektor nach dem Löschen aller Elemente leer ist.

Oder, wie durch einen Kommentar vorgeschlagen, könnten Sie die Kopie unter Verwendung einer while-Schleife vermeiden:

while (!CLEntity3D::vecEntity.empty()) 
{ 
    delete CLEntity3D::vecEntity.begin(); 
} 
+0

Überprüfen Sie den 'Clentity3D' Destruktor, es entfernt das aktuelle Element aus dem Vektor. – Dutow

+0

Ah, das habe ich vermisst. Ich denke, der Code ist zu kaputt, um ihn zu reparieren. – juanchopanza

+1

Speichern Sie sich die Kopie: 'while (! Clentity3D :: vecEntity.empty()) löschen Clentity3D :: vecEntity.begin();' – user4581301