Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

14.04.2015, 17:10

::operator delete[] und Destruktoren

Hallo :)
In Anbetracht eines OS in C++ implementiere ich gerade die operatoren new und delete. Dabei frage ich mich:
Rufe ich 'delete[] ptr' auf, lösche also ein array von elementen, wird ja ::operator delete[](void*) aufgerufen, der z.B. dann irgendeine Free()-Funktion benutzt.
Aber woher nimmt der Compiler die Information, wieviele Destruktoren aufzurufen sind? Ich hab etwas gegoogelt und lese, dass der Compiler ::operator new(size_t) mit der größe des zu allozierenden Speichers plus ein paar extra bytes aufruft, um in diesen extra bytes die arraygröße zu speichern. Bei delete[] ptr nimmt er dann diese Information und ruft entsprechend viele Desktruktoren auf.
Richtig? Brauch ich also nur ::operator new(size_t)/delete(void*)/delete[](void*) neu zu implementieren, die nur rohe Speicherblöcke alloziieren bzw. freigeben und ich mich nicht selbst um Konstruktor/Desktruktor kümmern? :hmm:

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

2

14.04.2015, 17:16

Nein, das ist voellig der Implementierung ueberlassen. man ruft new[] mit einem Parameter auf, was dann einen Pointer zurueck gibt mit n Elementen dahinter. Wenn delete[] mit diesem Pointer als Parameter aufgerufen wird, so muessen alle diese n Elmente zerstoert werden, woher die Implementierung dieses n bekommt, ist nach aussen hin egal. Du koenntest es z.b. in einer Tabelle nachschlagen. Bei einer schlauen Implementierung ergibt sich die Groesse aber vielleicht einfach durch die umliegenden Speicherbloecke etc...

Tobiking

1x Rätselkönig

  • Private Nachricht senden

3

14.04.2015, 17:47

Es ist schon richtig, dass der Compiler die die Destruktoren aufruft. Der Compiler erzeugt den Code für T::operator delete[] und ruft dort erst die Destruktoren auf und dann operator delete[], in der du nur noch den Speicher freigeben musst.

4

14.04.2015, 19:44

Ich muss mich also nur um das anfordern und freigeben kümmern, das Ermitteln der Anzahl der aufzurufenden Destruktoren ermittelt der Compiler also selbst.

5

20.04.2015, 19:57

Ich muss mich also nur um das anfordern und freigeben kümmern, das Ermitteln der Anzahl der aufzurufenden Destruktoren ermittelt der Compiler also selbst.

Nein! Ich empfehle die Lektüre von
https://molecularmusings.wordpress.com/2…-system-part-1/
https://molecularmusings.wordpress.com/2…-system-part-2/

und ggf. weitere Artikel aus der Serie. Da geht's zwar um die Implementierung eines eigenen (effizienteren) Memorysystems für Spiele, aber die grundlegenden Prinzipien sollten für dich trotzdem sehr interessant sein.

Tobiking

1x Rätselkönig

  • Private Nachricht senden

6

20.04.2015, 22:12

Ich muss mich also nur um das anfordern und freigeben kümmern, das Ermitteln der Anzahl der aufzurufenden Destruktoren ermittelt der Compiler also selbst.

Nein! Ich empfehle die Lektüre von
https://molecularmusings.wordpress.com/2…-system-part-1/
https://molecularmusings.wordpress.com/2…-system-part-2/

und ggf. weitere Artikel aus der Serie. Da geht's zwar um die Implementierung eines eigenen (effizienteren) Memorysystems für Spiele, aber die grundlegenden Prinzipien sollten für dich trotzdem sehr interessant sein.

Der erste Artikel bestätigt aber die Aussage von Roflo:

Zitat


The compiler must somehow know how many instances of type Test are to be deleted – otherwise it can’t call the instances’ destructors. So what almost every compiler does upon a call to new[] is the following:
...
When delete[] is used later on, the compiler inserts code which reads the number of instances N by going back 4 bytes from the given pointer, and calls the destructors in reverse order

Soweit ich weiß sind die einzigen Stellen bei denen man selber den (De-)Struktor aufrufen muss globale/statische Objekte und placement new. Beim normalen new/new[]/delete/delete[] erzeugt der Compiler selber den Code.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

7

20.04.2015, 22:21

Das weißt du falsch. Bei globalen und auch statischen Objekten muss man natürlich nicht selbst den Konstruktor/Destruktor aufrufen.

Tobiking

1x Rätselkönig

  • Private Nachricht senden

8

21.04.2015, 08:04

Das weißt du falsch. Bei globalen und auch statischen Objekten muss man natürlich nicht selbst den Konstruktor/Destruktor aufrufen.

Bedenke das ich hier von einem Betriebssystemkernel in C++ spreche. In einem user space Programm wird das natürlich übernommen. Der Programmeinstiegspunkt ist da nämlich nicht die main Methode, sondern eine Funktion aus der Runtime. Die sorgt dafür das Konstruktoren etc. aufgerufen werden bevor dann die main Methode aufgerufen wird.

Im Kernel hat man weder eine Runtime, noch wird irgendetwas vorher aufgerufen. Der Bootloader läd üblicherweise einfach das Kernel Image an die gewünschte Adresse und springt anschließend an eine Adresse.

Quellen:
http://wiki.osdev.org/Calling_Global_Constructors
http://www.lowlevel.eu/wiki/C%2B%2B#glob…atische_Objekte

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

9

21.04.2015, 13:08

Man aber auch in der Situation lieber die Sache so einrichten, dass die Kon-/Destruktoren automatischen laufen anstatt das von Hand zu tun.

Allerdings ist es in der Tat äußerst fragwürdig, wozu man das in einem Kernel verwenden sollte.
Im Zweifelsfall gibt es Placement New oder Hilfsklassen. (Ähnlich Optional)

10

21.04.2015, 15:23

Herzlichen Dank :)

Werbeanzeige