Importer:Error:WasEmpty
-
Ich bin mir nicht sicher aber ich glaube ein Pointer ist immer gleich gross, es geht nur darum eine Speicheradresse zu speichern.
Das Objekt befindet sich dann an der Speicheradresse auf die der Pointer zeigt.
Deswegen kannst du auch Pointer ziemlich billig per return uebergeben oder e.g. ein vector<class *> vec; machen um bei einer (Vergroesserung) des Vectors nur die Pointer und nicht die ganzen Objekte zu kopieren auf die die Pointer zeigen.
Was Speicherlecks angeht gibt es glaube ich 2 grundsaetzliche Probleme.
1. Du hast den Pointer die ganze Zeit noch in der Hand und vergisst einfach delete auzurufen.
2. Du verlierst den letzten Pointer der noch auf das Objekt zeigt und bist nicht mehr in der Lage delete aufzurufen.
Bsp.: vector<class *> vec;
Wenn der Vector out of scope geht oder mit vec.clear(); geleert wird hast du ein Speicherleck.
Du muesstest bei der Konstellation erst manuell mit einer Schleife durch alle Pointer gehen und einzeln delete aufrufen.Bsp.: vector<unique_ptr <class> > vec;
Hier hast du den std unique pointer der das Objekt automatisch wegraeumt sobald es out of scope geht.
Hier ist aber z.b. auch wichtig zu wissen, dass der Vector, wenn er als Member in einer Klasse deklariert wurde, erst out of scope geht, sobald das Objekt zerstoert wurde. <-- Das ist mir mal passiert.
-
Ruvi schrieb:
Was Speicherlecks angeht gibt es glaube ich 2 grundsaetzliche Probleme.
1. Du hast den Pointer die ganze Zeit noch in der Hand und vergisst einfach delete auzurufen.
2. Du verlierst den letzten Pointer der noch auf das Objekt zeigt und bist nicht mehr in der Lage delete aufzurufen.
Bsp.: vector<class *> vec;
Wenn der Vector out of scope geht oder mit vec.clear(); geleert wird hast du ein Speicherleck.
Du muesstest bei der Konstellation erst manuell mit einer Schleife durch alle Pointer gehen und einzeln delete aufrufen.Bsp.: vector<unique_ptr <class> > vec;
Hier hast du den std unique pointer der das Objekt automatisch wegraeumt sobald es out of scope geht.
Hier ist aber z.b. auch wichtig zu wissen, dass der vector wenn er als member in einer Klasse deklariert wurde erst out of scope geht sobald, dass Objekt zerstoert wurde. <-- Das ist mir mal passiert.Ja, das genau darum gehts mir. Wenn ich mich in demselben Scope befinde:
*int p_array = new int[10];
und delete [] p_array - wie von krümelkacker vorgeschlagen - aufrufe, wird nach meinem Verständis das komplette Array gelöscht, da die gesamte Arraygröße im Scope bekannt ist.
Sobald ich aber die Funktion verlasse und nur noch eine Adresse zurückgebe (Zeiger), dann weiß die nächste Funktion doch nicht, wie groß das Array ist, und sollte demnach nicht das gesamt Array freigeben können.
Man müsste dann wie von dir vorgeschlagen mittels einer Schleife die einzelnen Zeigerelemente löschen, habe ich es richtig verstanden?
-
Nein, ein delete[] reicht. Du hast immer nur einen Pointer, auch wenn du das im gleichen Scope machen würdest.
-
cooky451 schrieb:
Nein, ein delete[] reicht. Du hast immer nur einen Pointer, auch wenn du das im gleichen Scope machen würdest.
Ich bin aber schon in der zweiten Funktion - also nicht mehr im selben Scope.
*Edit: Achso, es reicht demnach nur die Anfangsadresse aufzulösen und das OS gibt alles Folgende frei? Woher weiß das OS, wie viel Bytes nachfolgend freigegeben werden müssen, wenn ich außerhalb des Scope bin? Oder ist das irgendwie bei der Übergabe (return) irgendwo hinterlassen?
-
Ein delete[] reicht aus.
Mir ist nicht ganz klar woher delete[] weiss wieviele Elemente im Array sind, aber ich wuerde vermuten diese Information befindet sich entweder im Pointer selbst oder an der Speicheradresse auf die der Pointer zeigt, also im Array selbst.
http://www.cplusplus.com/reference/new/operator delete[]/
"operator delete[] can be called explicitly as a regular function, but in C++, delete[] is an operator with a very specific behavior: An expression with the delete[] operator, first calls the appropriate destructors for each element in the array (if these are of a class type), and then calls function operator delete[] (i.e., this function) to release the storage."Im Grunde gilt, alles was mit "new" geholt wird, muss auch wieder mit delete oder delete[] geloescht werden, ansonsten hat man ein Speicherleck.
Bei meinem ersten Beispiel oben mit dem Vector of Pointers habe ich also einen Vector voller Pointer die auf Objekte zeigen die mit "new" geholt wurden.
Wenn der Vector jetzt out of scope geht oder ich vec.clear(); benutze werden alle Objekte die auf dem Stack liegen (die Pointer) ordnungsgemaess geloescht.
Allerdings liegen die Objekte die mit "new" geholt wurden auf dem Heap und dort wird es erst mit dem Befehl "delete" weggeraeumt.
Das bedeutet, dass diese Objekte erst manuell geloescht werden muessen bevor ich den letzten Pointer verliere der auf diese jeweiligen Objekte zeigt.
-
Ruvi schrieb:
Ein delete[] reicht aus.
Mir ist nicht ganz klar woher delete[] weiss wieviele Elemente im Array sind, aber ich wuerde vermuten diese Information befindet sich entweder im Pointer selbst oder an der Speicheradresse auf die der Pointer zeigt, also im Array selbst.
http://www.cplusplus.com/reference/new/operator delete[]/
"operator delete[] can be called explicitly as a regular function, but in C++, delete[] is an operator with a very specific behavior: An expression with the delete[] operator, first calls the appropriate destructors for each element in the array (if these are of a class type), and then calls function operator delete[] (i.e., this function) to release the storage."Danke, es klingt logisch, eventuell ist es im Array selbst hinterlassen.
-
Ruvi schrieb:
Mir ist nicht ganz klar woher delete[] weiss wieviele Elemente im Array sind, aber ich wuerde vermuten diese Information befindet sich entweder im Pointer selbst oder an der Speicheradresse auf die der Pointer zeigt, also im Array selbst.
Der Compiler (g++) reserviert +4 bytes (sizeof(size_t)) vor dem array und speichert dort die Anzahl der Elemente.
#include <iostream> #include <new> class test { int i; // 4 bytes public: test() {std::cout << "ctor" << std::endl;} ~test() {std::cout << "dtor" << std::endl;} void* operator new[](size_t n) { void* result; result = ::operator new[](n); std::cout << "operator new[] size:" << n << " at:" << result << std::endl; return result; } }; int main(int, char**) { test* p = new test[2]; std::cout << "new test[2] at:" << p << std::endl; delete[] p; return 0; }operator new[] size:12 at:0x7e1050 ctor ctor new test[2] at:0x7e1054 dtor dtor- osdt
-
Danke, gut zu wissen.
-
osdt schrieb:
Der Compiler (g++) reserviert +4 bytes (sizeof(size_t)) vor dem array und speichert dort die Anzahl der Elemente.
#include <iostream> #include <new> class test { int i; // 4 bytes public: test() {std::cout << "ctor" << std::endl;} ~test() {std::cout << "dtor" << std::endl;} void* operator new[](size_t n) { void* result; result = ::operator new[](n); std::cout << "operator new[] size:" << n << " at:" << result << std::endl; return result; } }; int main(int, char**) { test* p = new test[2]; std::cout << "new test[2] at:" << p << std::endl; delete[] p; return 0; }Danke für den Hinweis,
ich wollte gerade den Code testen. Mein VC++6 sagt allerdings, dass in Zeile 15 der Befehl new[] kein Element von 'global namespace' ist. Man müsste den Operator nicht aus std entnehmen, sondern global lassen?
-
Dann ist was falsch, denn der Code läuft: http://ideone.com/kCe65G
-
Danke, der Code läuft unter Netbeans einwandfrei ... schient irgendetwas mit meiner heißgeliebten VC6 IDE zu sein http://lug-ottobrunn.de/wiki/Operator_New_in_CPP
-
VC6 ??? Der zugehörige Compiler ist noch nicht mal C++98 konform.
Nimm doch einfach das aktuelle VS Express.
-
Th69 schrieb:
VC6 ??? Der zugehörige Compiler ist noch nicht mal C++98 konform.
Nimm doch einfach das aktuelle VS Express.Ja, werde dann nur noch mit VS2010 Express u. Netbeans arbeiten

Nichtsdestotrotz denke ich, dass der Code, den osdt gepostet hat, keinen wirklichen Beweis liefert, da das Ganze in einer Klasse eingebetet ist und die Klasse kraft ihres Amtes die Auflösung der Zeigerelemente einleitet.
Gibt es eventuell eine andere Möglichkeit hinter die Kulissen zu schauen, vielleicht mit einem Debugger oder so, wo man die Speicherzellen direkt sieht und zum Testen ansprechen könnte? Also, ohne Hilfe von Klassen u. Strukturen.
-
Cpp_Anfaeger schrieb:
Nichtsdestotrotz denke ich, dass der Code, den osdt gepostet hat, keinen wirklichen Beweis liefert, da das Ganze in einer Klasse eingebetet ist ...
Damit hast du Recht. Der Code beweist nur, dass die Anzahl Elemente vom Compiler gespeichert wird (und werden muss) wenn es sich um Datentypen (Klassen) mit destructor handelt. Vor dem Aufruf des eigentlichen operator delete[] muss der Compiler den destructor (~test()) für jedes einzelne Element aufrufen (siehe Ausgabe 2x 'dtor').
Meine Aussage ...Der Compiler (g++) reserviert +4 bytes (sizeof(size_t)) vor dem array und speichert dort die Anzahl der Elemente.
gilt also nur in diesem Fall.
Für native (POD) Datentypen wie char[] oder int[] gilt dieses jedoch nicht.
char* p = new char[10];wird also nur 10 Bytes reservieren.
- osdt
-
Dies ist unabhängig vom Datentyp - denn irgendwie muß die Freigabefunktion (delete[] bzw. free() bzw. betriebssystemabhängige Funktion) ja wissen, wieviel Speicher sie wieder freigeben muß (eine andere Alternative wäre, daß intern eine Mappingtabelle <Speicheradresse, Groesse> benutzt würde).
-
Ich denke, dass wir immer nich einen Speicherleck haben, trotz: delete [] zeiger
Ich weiß eigentlich nicht, ob folgender Code den Speicherleck beweist, der immer noch da ist, oder?
#include <iostream> using namespace std; int main(int argc, char** argv) { int *p_array = new int[10]; // Zeiger auf ein Array im Heap int *p_merker = p_array; // p_merker simuliert die Übergabe (return) for (int i = 0; i < 10; i++) { *p_array = i; p_array++; } p_array = p_merker; delete [] p_merker; // Übergabe-Zeiger wird mit eckigen Klammern gelöscht for (int j = 0; j < 10; j++) { // Arrays immer noch vollständig da cout << j << ".: " << *p_array << endl; p_array++; } return 0; }
-
Der Code ist UB.
Das funktioniert nur, weil das Betriebssystem den Speicher noch nicht recycelt hat.
-
Nathan schrieb:
Der Code ist UB.
Das funktioniert nur, weil das Betriebssystem den Speicher noch nicht recycelt hat.Kann man es irgendwie merken, wann das OS den Speicher leert - vielleicht selbst anstoßen?
-
OK danke, alles klar

#include <iostream> using namespace std; void dummy(){ int *p_array = new int[10]; for (int i = 0; i < 10; i++) { *p_array = i; p_array++; } delete [] p_array; } int main(int argc, char** argv) { int *p_array = new int[10]; // Zeiger auf ein Array im Heap int *p_merker = p_array; // p_merker simuliert die Übergabe (return) for (int i = 0; i < 10; i++) { *p_array = i; p_array++; } p_array = p_merker; delete [] p_merker; // Übergabe-Zeiger wird mit eckigen Klammern gelöscht for (int j = 0; j < 10; j++) { // Array immer noch vollständig cout << j << ".: " << *p_array << endl; p_array++; } cout << "---------------------" << endl; dummy(); for (int j = 0; j < 10; j++) { // Array immer noch vollständig cout << j << ".: " << *p_array << endl; p_array++; } return 0; }
-
Cpp_Anfaeger schrieb:
Nathan schrieb:
Der Code ist UB.
Das funktioniert nur, weil das Betriebssystem den Speicher noch nicht recycelt hat.Kann man es irgendwie merken, wann das OS den Speicher leert - vielleicht selbst anstoßen?
Ja, mit delete. Damit gibst du Speicher an das OS zurück.
Du darfst denn danach nicht mehr verwenden!
Ob das OS den Speicher schon erneut verwendet, hängt damit zusammen wie viele andere Prozesse Speicher anfordern etc..
Aber dir gehört er nicht mehr.
Und du darfst dich auch nicht darauf verlassen, dass ein erneuter Call zu new denselben Speicher zurückgibt!