Wieso reicht delete[] zum Löschen von Arrays?



  • Wenn ich ein Array mit new erstelle, wie kommt es, dass es beim Löschen ausreicht, einfach nur delete[] zu schreiben?
    Wieso ist die Angabe der Arraylänge nicht nötig? Woher weiß das Programm, wieviel Speicher es vom Heap wieder freigeben muss?

    Wurde die Arraylänge, die bei new angegeben wurde, irgendwo gespeichert?
    Wenn sie gespeichert wurde, kann man im Code auf diesen Wert zugreifen?


  • Mod

    Ja, wurde gespeichert. Nein, offiziell kannst du nicht da drauf zugreifen. Inoffiziell kannst du dich schlau machen, wie eine bestimmte Implementierung das macht und dieses Wissen dann nutzen. Beispielsweise speichern manche Implementierungen die Größe direkt vor Beginn des Bereichs. Verlass dich aber bloß nicht auf solche Hacks!

    Und falls du es nicht mitbekommen haben solltest: In C++ sollte es niemals vorkommen, dass du new/delete in Anwendungscode hast. Nutz Standardcontainer! Oder in dem seltenen Fall, dass sie dir nicht passen, bau eigene Container, die die grundlegenden Designprinzipien zur Ressourcenverwaltung in C++ (z.B. RAII) berücksichtigen.



  • OK, danke für die Antwort.



  • SeppJ schrieb:

    Beispielsweise speichern manche Implementierungen die Größe direkt vor Beginn des Bereichs. Verlass dich aber bloß nicht auf solche Hacks!

    Heute, viele Jahre später kann man durchaus argumentieren, dass es schon ein "Hack" im Standard ist, dass delete[] auf magische Weise die Grösse des Arrays kennen muss 😉

    Übrigens noch ein gutes Argument für hartnäckige Standardcontainer-Verweigerer, die meinen mit solchen lowlevel-Arrays schneller zu sein:
    Die benötigte Array-Grösse, um die Elemente korrekt zerstören zu können liegt bei den Standard-Containern meist auf dem "heißen" Stack und damit sehr wahrscheinlich im CPU-Cache.
    Muss man diese erst vom Anfang des "toten" Nutzdaten-Speicherbereichs laden ist die Wahrscheinlichkeit höher dass sie nicht im Cache liegt und man zusätzliche CPU-Zyklen verschwendet.

    Finnegan



  • Finnegan schrieb:

    SeppJ schrieb:

    Beispielsweise speichern manche Implementierungen die Größe direkt vor Beginn des Bereichs. Verlass dich aber bloß nicht auf solche Hacks!

    Heute, viele Jahre später kann man durchaus argumentieren, dass es schon ein "Hack" im Standard ist, dass delete[] auf magische Weise die Grösse des Arrays kennen muss 😉

    Warum?



  • manni66 schrieb:

    Finnegan schrieb:

    SeppJ schrieb:

    Beispielsweise speichern manche Implementierungen die Größe direkt vor Beginn des Bereichs. Verlass dich aber bloß nicht auf solche Hacks!

    Heute, viele Jahre später kann man durchaus argumentieren, dass es schon ein "Hack" im Standard ist, dass delete[] auf magische Weise die Grösse des Arrays kennen muss 😉

    Warum?

    Darum.



  • SeppJ schrieb:

    Und falls du es nicht mitbekommen haben solltest: In C++ sollte es niemals vorkommen, dass du new/delete in Anwendungscode hast.

    Pah, wenn ich es für notwendig erachte, benutze ich es immer.
    Wieso nicht, wenn man weiß damit umzugehen?



  • EOP schrieb:

    SeppJ schrieb:

    Und falls du es nicht mitbekommen haben solltest: In C++ sollte es niemals vorkommen, dass du new/delete in Anwendungscode hast.

    Pah, wenn ich es für notwendig erachte, benutze ich es immer.
    Wieso nicht, wenn man weiß damit umzugehen?

    🙄



  • manni66 schrieb:

    Finnegan schrieb:

    Heute, viele Jahre später kann man durchaus argumentieren, dass es schon ein "Hack" im Standard ist, dass delete[] auf magische Weise die Grösse des Arrays kennen muss 😉

    Warum?

    Ich empfinde es schon als etwas "hackig" alles durch ein void* -Interface ohne Typ-, Größen- oder Alignment-Informationen zu stopfen,
    so dass Implementationen selbst schauen müssen, wo sie die Informationen her bekommen, und dann zu solchen "Tricks" greifen, wie die Größe
    des Arrays vor den Nutzdaten zu speichern. Dass da durchaus was dran ist, sieht man u.a. auch an den neuen Signaturen, die delete und delete[]
    mit C++14/17 spendiert bekommen. Damals hat man sich einfach noch zu sehr an purem malloc / free orientiert.



  • theta schrieb:

    🙄

    Jetzt mal nicht frech werden, junger Mann. 🙂



  • Wie mach ich denn das schlauer? Mit einem Container? Wenn ich einen will wende ich mich an Hanjin, und die sind mit über 5 Mrd. auch pleite gegangen:

    // keywords
    	KeyWordsData *keywords_data = new KeyWordsData;
    	if( keywords_data )
    	{
    		//keywords_data->fail_keywords = thePrefs.;
    		keywords_data->success_keywords = new CStringA( thePrefs.success_kw_edit_ascii );
    	}
    
    	// send new data to the thread
    	if( !::PostThreadMessage(threadID, UWM_SETTINGS_AND_KEYWORDS_DATA, (WPARAM)settings_data, (LPARAM)keywords_data) )
    	{ /* failed */
    		//TRACE(_T("Image Thread 0x%02x UWM_GET_HTTP/ALL task failed\n"), m_test_thread.threadID);
    		delete settings_data->proxy;
    		delete settings_data;
    
    		//delete keywords_data->fail_keywords;
    		delete keywords_data->success_keywords;
    		delete keywords_data;
    		return( false );
    	} /* failed */
    


  • Du kannst trotzdem ne Helperstruct entwerfen, ähnlich std::unique_ptr, der das ganze automatisch deleted. Das zu LPARAM etc zu casten ist zwar ziemlich genau undefiniertes verhalten, aber sollte funktionieren. Schließlich enthält dieses Object lediglich nen Zeiger auf die Daten.

    Ohne dieses casten täts auch eine Liste, wobei dann lediglich ein zeiger auf das Element mitgegeben wird, was dann beim Eintreffen wieder entfernt werden kann. Könnte bei C-Verehrern allerdings auf Naserümpfen aufgrund des 'Overheads' stoßen.



  • Techel schrieb:

    Du kannst trotzdem ne Helperstruct entwerfen, ähnlich std::unique_ptr, der das ganze automatisch deleted.

    Und wie? Das würde mich auch interessieren, hatte ziemlich das selbe Problem nämlich auch schon ein paar mal.

    std::unique_ptr deleted ja einfach im destruktor, also wenn er out of scope geht... das geht in dem Fall ja nicht.

    Techel schrieb:

    Das zu LPARAM etc zu casten ist zwar ziemlich genau undefiniertes verhalten, aber sollte funktionieren.

    Klingt nicht gerade zufriedenstellend...



  • Wenn PostThreadMessage scheitert ist die Vorgehensweise ja schon gezeigtt. Der Rest sollte klar sein. Delete passiert dann beim Empfänger.



  • EOP schrieb:

    Wenn PostThreadMessage scheitert ist die Vorgehensweise ja schon gezeigtt. Der Rest sollte klar sein.

    Wenn der Rest klar ist, warum fragst du dann "Wie mach ich denn das schlauer?" 😕

    Mir ist aber auch nicht klar wie ich das gezeigte mit einem smart-pointer realisieren kann, deswegen die Frage (wie ich es mit standard new/delete mache ist klar aber darum ging es ja nicht).



  • Bei den delete Anweisungen mit -> drinnen sollte wohl klar sein wie man sie los wird: unique_ptr als Member verwenden.
    Und bei den anderen beiden kann auch unique_ptr helfen: einfach statt "if Fehler -> delete" den Code zu "if Erfolg -> release" umbauen.



  • hustbaer schrieb:

    Bei den delete Anweisungen mit -> drinnen sollte wohl klar sein wie man sie los wird: unique_ptr als Member verwenden.
    Und bei den anderen beiden kann auch unique_ptr helfen: einfach statt "if Fehler -> delete" den Code zu "if Erfolg -> release" umbauen.

    Hm, release hab ich bis jetzt noch nie verwendet... scheint höchste Zeit zu werden 👍



  • c

    hustbaer schrieb:

    Bei den delete Anweisungen mit -> drinnen sollte wohl klar sein wie man sie los wird: unique_ptr als Member verwenden.
    Und bei den anderen beiden kann auch unique_ptr helfen: einfach statt "if Fehler -> delete" den Code zu "if Erfolg -> release" umbauen.

    Du meinst, das funktioniert auch in einem anderen thread.
    Sorry for hijacking this thread. Wäre eigentlich ein MFC-Thema.



  • SeppJ schrieb:

    Und falls du es nicht mitbekommen haben solltest: In C++ sollte es niemals vorkommen, dass du new/delete in Anwendungscode hast.

    wieso? Wenn ich mir einen Kugelschreiber kaufe, werfe ich deshalb doch auch nicht alle Bleistifte weg.



  • Dumpfbackenhausen


Log in to reply