2010-07-27 4 views
13

Ich suchte StackOverflow, aber konnte die Antwort auf diese Frage nicht finden.Was ist der richtige Weg, um einen Zeiger std :: Zeiger in C++ zu befreien?

Angenommen, ich habe eine std::vector<Day *> vector_day - das heißt - ein Vektor von Zeigern zu Day Objekt. Jetzt habe ich push_back zu vector_day viele Elemente:

vector_day.push_back(new Day(12)); 
vector_day.push_back(new Day(99)); 
vector_day.push_back(new Day(71)); 
... 

jetzt irgendwann nicht mehr brauche ich vector_day. Was ist der richtige Weg, um die Erinnerung zu befreien?

Es dies der richtige Weg:

for (std::vector<Day *>::iterator i = vector_day.begin(); i != vector_day.end(); ++i) { 
    delete *i; 
} 

Enthält diese auf jedem Löschen des Vektors nicht ungültig machen? Ich bin sehr verwirrt.

+0

Kann ein Betrogene von http://stackoverflow.com/questions/3054567/right-way-to-deallocate-an-stdvector-object –

+0

RC - nicht wirklich, das ist völlig anders. – bodacydo

+1

Zeig nicht so hinein. Was passiert, wenn eine Ausnahme zwischen der Zeit, in der sich das Material im Vektor befindet, und dem Ort, an dem Sie alles löschen, geworfen wird? Du würdest es überspringen und undicht werden. Verwenden Sie einen intelligenten Zeiger oder einen Zeigercontainer, niemals rohe Zeiger. – GManNickG

Antwort

16

Der beste Weg ist, Zeiger nicht in den Vektor in erster Linie zu setzen, wenn Sie nicht unbedingt müssen.

Aber wenn Sie wirklich einen Vektor von Zeigern haben müssen, dann ist die Art, wie Sie es tun, in Ordnung (aber .clear() der Vektor nach, wenn es nicht sofort zerstört wird, so dass es nicht voller baumeln ist Zeiger)

die Aussage

delete *it; 

hat keine Auswirkung auf den Iterator. Es ändert den Iterator nicht, macht den Iterator ungültig oder entfernt den Zeiger, auf den der Iterator verweist, aus der Sammlung. Es gibt nur den Speicher frei, auf den der Zeiger, auf den der Iterator verweist, zeigt. Der Zeiger selbst muss separat aus der Sammlung entfernt werden.

+0

Danke für die Erklärung. Wenn der Vektor den Gültigkeitsbereich verlässt, wird der Zeiger automatisch entfernt, oder? – bodacydo

+1

@bodacydo: Richtig. Wenn Sie die 'delete * it'-Aufrufe machen, bevor der' vector' den Gültigkeitsbereich verlässt, machen Sie sich keine Sorgen über den Aufruf von 'clear()'. –

0

Operationen, die Elemente aus dem Array hinzufügen oder entfernen, können die Iteratoren ungültig machen. Überprüfen Sie die Dokumentation auf bestimmte Regeln für die verschiedenen Containertypen. Mit delete handeln Sie mit den Daten in den Array-Elementen und nicht mit der Form des Arrays. Iteratoren durchlaufen die Form des Containers, sie interessieren sich nicht für den Inhalt.

+0

Ich verstehe jetzt die Ungültigkeit besser. Danke für deine Antwort! – bodacydo

0

Als erstes wechselten Sie von i zu it, aber ich nehme an, das ist nur ein Tippfehler.

Aber um deine Frage zu beantworten, nein, das ist in Ordnung. Sie ändern nicht it, Sie ändern *it.

+0

Ich korrigierte den Fehler, dass 'es' für' i' verwendet wurde. Danke, dass du es gesehen hast. Was passiert, wenn ich 'i = 0xAABBCCDD' in der Schleife - das ändert eindeutig' i' und nicht 'it', würde das den Vektor ungültig machen? – bodacydo

1

Sie sollten wahrscheinlich einen verwalteten Zeiger verwenden, höchstwahrscheinlich einen gemeinsamen Zeiger.

Wenn Sie den Vektor löschen, während sich jemand anderes noch an einem dieser Zeiger festhält, werden Sie ein sehr unangenehmes Verhalten bekommen, wenn Sie versuchen, es zu dereferenzieren. Ein gemeinsamer Zeiger wird Ihnen diese Kopfschmerzen ersparen.

Wenn Sie garantieren können, dass nach dem Löschen des Vektors nichts mehr auf die Zeiger verweist, können Sie dennoch einen automatischen Zeiger verwenden. Es wird die Deallokation für Sie verwalten, wenn der Vektor zerstört wird. Der Aufwand ist minimal, und es macht Ihr Leben viel einfacher.

+0

Ich würde für unique_ptr, sicherlich nicht auto_ptr gehen. – Gabriel

0

Es ist in Ordnung. Sie löschen *i (das Objekt, auf das das Vektorelement zeigt) und nicht i (Element des Vektors), so dass der Vektor nicht ungültig gemacht wird.

Siehe this question für einen Fall, in dem der Entwickler auch alle i s löschen wollte, und für die Lösung dafür (vector_day.clear()) nach der Schleife.

3

Eine andere C++ Weg, dies zu tun, ist ein Helfer-Struktur zu definieren:

struct delete_ptr { // Helper function to ease cleanup of container 
    template <typename P> 
    void operator() (P p) { 
     delete p; 
    } 
}; 

und dann die Algorithmen verwenden:

std::for_each(vector_day.begin(), vector_day.end(), delete_ptr()); 
vector_day.clear(); 
2

Im Allgemeinen in C++ Sie Speicherverwaltung so viel wie möglich verstecken sollte um Speicherfehler zu vermeiden. Wenn Sie nicht viel von den Zeigern kopieren und viel Wert auf Leistung legen, würde ich einfach shared_ptr verwenden.

Es ist Teil des TR1-Standards und ist in den meisten modernen C++ - Compilern sofort verfügbar (http://anteru.net/2008/09/01/260/) und eignet sich hervorragend für Brand- und Speicherverwaltung.

+1

Oder zuerst sollten Sie sich unique_ptr ansehen. – DanDan

5

Boost ptr_vector zur Rettung!

tut genau das, was Sie brauchen, ohne die Notwendigkeit

0

Hier ist eine handliche Klasse I vor einer Weile geschrieben, während mit dem gleichen Problem, den Inhalt des std :: vector iterieren und löschen zu tun. Ich habe einen Code von alten RogueWave-basierten Vektoren und Listen in STL-basierte Vektoren und Listen konvertiert und brauchte eine Methode, um RWs clearAndDestroy() -Methode für Zeigerlisten zu emulieren. Die clearAndDestroy() -Methode kann überschrieben werden, um verschiedene Strukturtypen zu behandeln (ich habe hier aus Platzgründen nur einen Vektor eingefügt).

class StlUtils 
{ 
    public: 

     /** 
     * This method provides a templated way to destroy a std::vector 
     * full of pointers. It is basically a replacement for the RW 
     * vector class' clearAndDestroy methods. The list argument is 
     * returned empty. 
     * 
     * @param list the list of pointers to be destroyed. 
     */ 
     template<class T> static void clearAndDestroy(
     std::vector<T*> &itemList) 
     { 
     for_each(itemList.begin(), itemList.end(), 
        stl_deleter<T>()); 
     itemList.clear(); 
     } 

    private: 

     /** 
     * Templated member function for use with the clearAndDestroy() 
     * method. It provides the method needed by for_each to do the 
     * actual deletion. 
     */ 
     template<class T> struct stl_deleter 
     { 
     void operator() (T* x) { 
      if (x != NULL) 
       delete x; 
     } 
     }; 
}; 
+0

Sie dürfen Nullzeiger löschen (was nichts tut), so dass das if nicht wirklich benötigt wird. – ollb