Importer:Error:WasEmpty
-
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!
-
@Cpp_Anfaeger
Zum Vermeiden solcher Fehler gibt es gute Hilfsmittel, wie z.B. die Debug-Heap Funktionen unter Windows.
Mittels derer kann man es einrichten dass freigegebener Speicher mit einem bestimmten Muster gefüllt wird (üblicherweise0xdddddddd). Visual C++ aktiviert diese Funktionen per Default inRelease-BuildsDebug-Builds.Und wenn dein Programm in einer solchen Umgebung läuft, würdest du anhand der "komischen Zahlen" die von der 2. Ausgabeschleife ausgegeben werden merken dass etwas nicht so läuft wie es sollte.
Auf Linux gibt es vermutlich ähnliche Funktionen/Tools. Bzw. auch Programme wie valgrind, die helfen können solche (und andere) Fehler zu finden.
EDIT: Blödsinn korrigiert.
-
hustbaer schrieb:
in Release-Builds.
Bist du dir sicher dass das im Release so ist und nicht im Debug-Build?
Ich kann mich auch irren, möchte nur dazulernen...
-
Nein, gar nicht. Ganz im Gegenteil.
Ich bin mir sicher dass ich Blödsinn geschrieben habe.
Danke für den Hinweis!
-
Th69 schrieb:
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).
Natürlich, die zugrunde liegende C/C++ runtime library muss wissen wieviel Speicher freigegeben wird. Normalerweise werden diese Informationen in dem Speicherbereich direkt vor dem zurückgelieferten pointer platziert. Man nennt das auch 'malloc overhead'.
Das hat aber nichts mit dem Compiler zu tun. Der Compiler muss nur wissen aus wievielen Elementen das Array besteht, wenn er vor operator delete[] den Destructor jedes einzelnen Elementes aufrufen muss. In dem Fall reserviert der Compiler 4 Bytes extra (bei 32Bit) um die Anzahl Elemente zu speichern.
- osdt
-
Cpp_Anfaeger schrieb:
Ich denke, dass wir immer nich einen Speicherleck haben, trotz: delete [] zeiger
Du traust der C/C++ runtime library nicht, oder?
Wenn new[]/delete[] oder malloc()/free() nicht funktionieren würden, hätten wir nicht ein lauffähiges C/C++ Programm.
Wenn Du genau wissen willst weshalb es doch funktioniert, schau dir mal den Quelltext einer open source C/C++ Bibliothek an. Man kann viel dabei lernen.
- osdt