Element aus Vektor löschen und Speicher freigeben



  • Ich habe einen Vektor mit Zeigern auf Elemente einer Klasse. Die Elemente des Vektors müssen also mit new() erstellt werden.

    #include <vector>;
    using namespace std;
    
    class CTest {
    	double asd;
    };
    
    int main() {
    	vector<CTest*> test;
    	for (int i = 0; i < 5000000; ++ i)
    		test.push_back(new CTest());
    	system("PAUSE");
    }
    

    Wenn ich später aber Elemente des Vektors mit erase() lösche, wird der Speicher nicht wieder freigegeben. Muss ich die Elemente zusätzlich noch mit delete löschen? Das habe ich nämlich versucht:

    for (int i = 0; i < 5000000; ++ i)
    	delete test[i];
    

    Der Speicher wird dadurch aber auch nicht freigegeben. Was muss ich also machen?





  • Danke, aber ich würde gerne nur einzelne Elemente des Vektors löschen. Geht das auch?



  • Die Objekte hast du mit new angelegt, also mußt du sie auch mit delete wieder freigeben. Alternativ kannst du auch boost::shared_ptr bzw. tr1::shared_ptr in den vector packen oder einen ptr_vector verwenden.



  • snOOfy schrieb:

    Wenn ich später aber Elemente des Vektors mit erase() lösche



  • @CStoll: Mit boost würde es wohl gehen, aber ich würde es gerne ohne hinbekommen. Wie muss ich die Objekte denn mit delete löschen? So wie ich es versucht habe (siehe oben) hat es ja nicht funktioniert.

    @TyRoXx: Und wie soll mir das jetzt helfen? Wenn du den zitierten Satz zu Ende liest, dann siehst du, dass es mit erase() auch nicht geklappt hat. Habe ich es vielleicht falsch gemacht?

    for (int i = 5000000 - 1; i >= 0; -- i)
    	test.erase(test.begin() + i);
    


  • snOOfy schrieb:

    Ich habe einen Vektor mit Zeigern auf Elemente einer Klasse. Die Elemente des Vektors müssen also mit new() erstellt werden.

    Falsch. Müssen sie nicht. Können aber.

    snOOfy schrieb:

    vector<CTest*> test;
    	for (int i = 0; i < 5000000; ++ i)
    		test.push_back(new CTest());
    	system("PAUSE");
    

    Wenn ich später aber Elemente des Vektors mit erase() lösche, wird der Speicher nicht wieder freigegeben. Muss ich die Elemente zusätzlich noch mit delete löschen?

    Dem Vektor ist das schei*egal, was er da speichert. Für Zeiger gibt es keine Sonderbehandlung. Wenn ein (normaler, roher) Zeiger zerstört wird, wird nicht automatisch auch der Speicher freigegeben, auf den er zeigte.

    snOOfy schrieb:

    Das habe ich nämlich versucht:

    for (int i = 0; i < 5000000; ++ i)
    	delete test[i];
    

    Der Speicher wird dadurch aber auch nicht freigegeben.

    Wie willst Du das denn festgestellt haben?



  • Wie willst Du das denn festgestellt haben?

    Im Windows-Taskmanager sehe ich, dass das Programm nach der Löschaktion immernoch 730MB Arbeitsspeicher belegt, genau wie vorher.


  • Mod

    snOOfy schrieb:

    Wie willst Du das denn festgestellt haben?

    Im Windows-Taskmanager sehe ich, dass das Programm nach der Löschaktion immernoch 730MB Arbeitsspeicher belegt, genau wie vorher.

    Und was hat das miteinander zu tun?

    (Tipp: Nichts)



  • volkard schrieb:

    test.clear();
    

    http://www.cplusplus.com/reference/stl/vector/clear/

    es ist nur garantiert, dass nach dem aufruf von clear() die größe des vektors (size()) null ist, nicht aber dessen capacity.

    die standardlösung dafür ist

    vector<T>().swap(other_vector);
    

  • Mod

    davie schrieb:

    die standardlösung dafür ist

    vector<T>().swap(other_vector);
    

    Man sollte aber betonen, dass dies nicht die Standardlösung zum Löschen der Vectorelemente ist, sondern die Standardlösung für den eher speziellen und seltenen Fall in dem man die capacity des Vectors ebenfalls auf 0 setzen möchte.



  • SeppJ schrieb:

    Und was hat das miteinander zu tun?
    (Tipp: Nichts)

    Im Laufe der Zeit werden in meinem Vektor immer mehr Elemente erstellt und alte gelöscht. Die Anzahl der Elemente bleibt ungefähr gleich. Trotzdem verbraucht das Programm aber immer mehr Arbeitsspeicher, bis es bei 2GB schließlich abstürzt. Wie hat das jetzt nichts damit zu tun, dass der Speicher meiner Vektorelemente nicht freigegeben wird? Genau das führt doch zu dem Problem, oder nicht?

    Vielleicht stelle ich mich ja ein bisschen blöd an, aber was genau muss ich denn jetzt machen, damit immer gleich viel Arbeitsspeicher belegt bleibt (nämlich genau der, der für die vorhandenen Elemente des Vektors benötigt wird)?



  • snOOfy schrieb:

    Im Laufe der Zeit werden in meinem Vektor immer mehr Elemente erstellt und alte gelöscht. Die Anzahl der Elemente bleibt ungefähr gleich. Trotzdem verbraucht das Programm aber immer mehr Arbeitsspeicher, bis es bei 2GB schließlich abstürzt.

    Dann hast Du an anderer Stelle ein Speicherleck. Solange die Kapazität nicht wachsen muss, werden die Elemente eines Vektors immer recycled. Vielleicht machst Du bei der Freigabe des Freispeichers mittels delete was falsch.



  • Das hier ist der gesamte Code:

    #include <vector>;
    using namespace std;
    
    class CTest {
    	double asd;
    };
    
    int main() {
    	vector<CTest*> test;
    	for (int i = 0; i < 2000000; ++ i)
    		test.push_back(new CTest());
    	system("PAUSE");
    
    	for (int i = 2000000 - 1; i >= 0; -- i)
    		delete test[i];
    	system("PAUSE");
    }
    

    Mache ich da bei delete was falsch?



  • snOOfy schrieb:

    Das hier ist der gesamte Code:

    #include <vector>;
    using namespace std;
    
    class CTest {
    	double asd;
    };
    
    int main() {
    	vector<CTest*> test;
    	for (int i = 0; i < 2000000; ++ i)
    		test.push_back(new CTest());
    	system("PAUSE");
    
    	for (int i = 2000000 - 1; i >= 0; -- i)
    		delete test[i];
    	system("PAUSE");
    }
    

    Mache ich da bei delete was falsch?

    Der Code verbaucht auf typischen 32 Bit Systemen knapp 23 MB. Wie Du damit 2 GB voll bekommst, erschließt sich mir nicht.



  • Jedenfalls ist klar, warum du beim zweiten system("PAUSE") immer noch einiges an Speicher benötigst (laut TaskMgr). Da du zwar die Objekte gelöscht hast, aber immer noch alle Zeiger im Speicher hast (auch wenn diese Zeiger jetzt auf ungültigen Speicher zeigen). Nach der for-Schleife musst du noch vec.clear() bzw. zum endgültigen Bereinigen (= vec.capacity() ==0) musst du die Zeile mit dem swap einfügen.

    MfG SideWinder



  • snOOfy schrieb:

    Mache ich da bei delete was falsch?

    Sollte so klappen, sofern 'int' solch große Zahlen fassen kann (was nicht garantiert ist, btw). Es ist aber eher sinnfrei in diesem Fall konkreten Beispiel new/delete zu verwenden. Ich frage micht, was Dir diese Indirektion bringt. Du kannst doch auch gleich die CTest-Objekte im Vektor speichern, statt Zeiger...

    Viele kleine "popelige" Objekte per new Erzeugen, würde ich vermeiden, wenn's geht. So verbrätst Du wahrscheinlich 20 Bytes pro Objekt (nur geraten, 8 Bytes für's double, 8 bytes für Freispeicher-Verwaltungsoverhead und 4 bytes für ein Zeiger, 32bit-System angenommen) und das Speicher anfordern/freigeben kostet auch Zeit. Da ist das Kopieren im Vergleich dazu bei einem "popeligen" double nicht schlimm.



  • Hallo Tachyon,

    dass Du alles löschtst ist ja nur in Deinem Beispiel so. Im effektiven Code willst Du ja einzelne Elemente löschen.

    for (int i = 2000000 - 1; i >= 0; -- i)
       {
         CTest* heapItem = test[i];
         test.erase (test.begin () + i);
         delete heapItem;
       }
    

    Ich habe das mit dem 'heapItem' absichtlich so gemacht damit ersichtlich wird, dass zwei Dinge gelöscht werden müssen.

    1. Das Item im Vector
    2. Das Item auf dem Heap

    Herzliche Grüsse
    Walter



  • @Tachyon: 2GB verbraucht es nicht hier im Beispiel sondern in meinem richtigen Programm, in dem die Elemente des Vektors Instanzen einer deutlich komplexeren Klasse sind.

    @weicher: Danke, so funktioniert es 🙂

    @krümelkacker: Danke für den Hinweis, ich habe nicht bedacht, was das für einen Overhead produziert. 😮 Jetzt habe ich es auch mal ohne Zeiger umgesetzt und verglichen, der Unterschied ist wirklich gigantisch.

    #include <vector>;
    using namespace std;
    
    class CTest {
    	double asd;
    public:
    	CTest(double asd) { this->asd = asd; };
    };
    
    int main() {
    	// Möglichkeit 1 ohne Zeiger (10sec, 20mb Speicher)
    	vector<CTest> test1;
    	for (int i = 0; i < 2000000; ++ i) {
    		test1.push_back(CTest(i));
    	}
    	for (int i = 2000000 - 1; i >= 0; -- i) {
    		test1.erase(test1.begin () + i);
    	}
    
    	// Möglichkeit 2 mit Zeigern (5min, 170mb Speicher)
    	vector<CTest*> test2;
    	for (int i = 0; i < 2000000; ++ i)
    		test2.push_back(new CTest(i));
    	for (int i = 2000000 - 1; i >= 0; -- i) {
    		CTest* heapItem = test2[i];
    		test2.erase(test2.begin () + i);
    		delete heapItem; 
    	}
    	system("PAUSE");
    }
    


  • Wenn du große Objekte speicherst und der Vektor oft umkopiert wird (z.B. durch wahlfreies Löschen), ist die Heap-Variante aber wieder deutlich schneller.


Anmelden zum Antworten