operator new[] verändert Rückgabepointer



  • New[] schrieb:

    Hi, wer kann mir erklären warum der operator new[] unter zumindest GCC eigenständig den Rückgabepointer um 8 Bytes? verschiebt.

    Für den Aufruf des operators delete[] muss der Compiler wissen, aus wievielen Elementen das Array besteht um den Destructor für jedes Element aufrufen zu können. Alle mir bekannten Compiler speichern diesen Wert am Anfang des (mit new[]) reservierten Speicherbereiches.



  • -Hinfällig


  • Mod

    1. Dein Code ist ablenkend unsinnig. Der Operand von delete kann nicht void* sein (sogar explizit in Fußnote 82 aufgeführt), was dir auch (auch unter GCC ggf. unter Mitgabe entsprechender aber ohnehin unverzichtbarer Flags) diagnostiziert werden sollte. Überdies ist der Aufruf an delete undefiniert, weil das Array durch malloc alloziert worden ist, und nicht ::operator new . (Der relevante Text wurde in einem commit gekürzt, der die Redundanz desselben anführt. Ich gehe also davon aus, dass die selbe Bedingung gilt.)

    2. Der Grund, aus dem im zweiten Beispiel die Größe des Arrays vom Compiler gespeichert wird (nicht ein vtable pointer), ist der, dass der Destruktor des Elementtyps nicht trivial ist; Lass virtual weg und überzeige dich selbst. Siehe [expr.delete]/10. Der Compiler muss folglich bei der Zerstörung des Arrays nicht nur den Speicher freigeben lassen, wofür das Betriebssystem eigene Strukturen hat, sondern auch die Destruktoren aufrufen. Dabei kann er nicht auf die in den OS Strukturen enthaltenen Array Boundaries zugreifen, denn das wäre eine layer violation. Siehe bspw. https://godbolt.org/g/RHS1uN, wo in Label L13 die Schleife zu finden ist, die alle Destruktoren aufruft.



  • Ach Leute ich hatte den Code nur schnell bei Ideone.com in das Standard Fenster gepasted und in ein Minimal Beispiel geändert. Fällt sonst noch jemandem etwas sinnvolles ein außer einem namespace der nicht verwendet wird.

    Im übrigen ist das include sehr wohl notwendig, da man ansonsten folgende Meldung bekäme:

    error: declaration of ‘operator new’ as non-function
    void* operator new(size_t size)

    Also denkt doch erstmal nach bevor ihr so eine schei... hier schreibt. Das macht mich mitlerweile echt wütend. Nichts konstruktives beitragen können, aber alle Threads mit irgendeinem dummen gelaber vollspammen.

    Klar die deletes hätte ich auch noch weglöschen sollen. Dann hätten die selben Klugscheißer hier aber geschrieben, dass es Memory Leaks gibt. Mann mann man was für korrinten Kack.. hier unterwegs sind. Das ändert übrigens alles nichts am Verhalten des operators new[]. Und das war die einzige Frage auf die ich eine Anrwort wollte. Kein Wunder das das Forum hier am sterben ist...



  • Dann aber den richtigen Include benutzen: <new>, s.a. operator new (und nicht darauf hoffen, daß dieser schon irgendwie über <iostream> (oder andere) eingebunden wird).

    Und osdt_ hat dir doch die richtige Antwort geschrieben!



  • Aber wie soll das funktionieren. der operator new[] verschiebt, den Zeiger ja in den Datenbereich hinein. Von mir aus kann er vor den Daten etwas schreiben und dafür mehr Speicher allokieren, aber doch nicht einfach den von malloc zur Verfügung gestellten Datenteil überschreiben. In der richtigen Applikation allokiere ich nämlich malloc(sizeof(Header) + size) und speichere meinerseits bereits Header-Informationen für den MemoryManager am Anfang des Arrays. Was genau passiert also in dem Moment wo der operator new[] den Zeiger manipuliert? Sollte ich also malloc(8 + sizeof(Header) + size) allokieren damit es richtig funktioniert?



  • Ich schlage vor dass du dir den size Wert den der Compiler an deinen operator new[] übergibt mal genauer anschaust. Und informier dich vielleicht auch über den Unterschied zwischen einer allocation function ( operator new ) und dem new Operator. Ansonsten wurde von Arcoth eh schon alles erklärt...



  • Ich verstehe das Problem nicht. Es werden 8 Byte mehr angefordert als für das Array benötigt werden. Diese 8 Byte benutzt das System für sich. Wenn du ebenfalls Informationen in dem Block unterbringen möchtest, forderst du entsprechend mehr Bytes mit malloc an und lieferst einen Zeiger auf den Speicher hinter deinem Header aus.



  • manni66 schrieb:

    Ich verstehe das Problem nicht.

    Das Problem hier ist rein psychologischer Natur. OP hat eine sehr feste Vorstellung davon wie genau etwas zu funktionieren hat und ist nicht bereit, diese zu hinterfragen. Stattdessen kommt er zur Schlussfolgerung dass, wenn das beobachtete Verhalten nicht seinen Erwartungen entspricht, eher was am Compiler falsch sein muss als an seinen Erwartungen. Aber wir schreiben hier eh alle nur schei... also whatever... 😉


  • Mod

    New[] schrieb:

    Klar die deletes hätte ich auch noch weglöschen sollen. Dann hätten die selben Klugscheißer hier aber geschrieben, dass es Memory Leaks gibt. Mann mann man was für korrinten Kack.. hier unterwegs sind. Das ändert übrigens alles nichts am Verhalten des operators new[]. Und das war die einzige Frage auf die ich eine Anrwort wollte. Kein Wunder das das Forum hier am sterben ist...

    Dann solltest du dich in diesem Fall einfach aufs Wesentliche beschränken. Die eigentliche Frage hattest du dir ja schon selbst (falsch) beantwortet. Dieses Unterforum ist auch nicht NadrW. Aus Unwissenheit zu insinuieren, dass dunkle Mächte aus reiner Bosheit Zeiger manipulieren, senkt das Niveau deiner Frage enorm. Vielleicht solltest du auch bedenken, dass Rücksichtnahme - die du ja hier einforderst - nur auf Gegenseitigkeit beruhen kann.



  • Du scheinst irgendwie die Funktionsweise von new[] nicht richtig zu verstehen.
    Dieser Operator ist nur dafür da, genug Speicher zu allokieren, d.h. daher wird einfach nur size übergeben (daher ist in deinem Beispielcode dieser Wert auch 344, d.h. um 8 größer als 42*8 [=336]), d.h. die Speicherverwaltungsmethode erhöht diesen Wert beim Aufruf). Innerhalb des Operator new[] darfst du also nicht davon ausgehen, daß du dort schon Nutzdaten in den Speicherbereich schreiben darfst)!
    Erst in deinem Anwendercode über den dort zurückgegebenen Zeiger darfst du auf diesen Speicherbereich (User data) zugreifen.

    Wenn du selber schon eigene Speicherverwaltungsinfos innerhalb des new[]-Operators hinzufügst, kommst du also mit der des Compilers in Konflikt.

    Du kannst aber "sizeof(Header) + size" per malloc allozieren, dann solltest du zwingend "static_cast<char *>(value) + sizeof(Header)" als Rückgabewert des new[]-Operators angeben (und dann natürlich den dazu passenden operator delete[] implementieren).
    Die Daten im Speicher wären also:
    - Header
    - Größe des Arrays (8)
    - User data



  • Naja, die Umsetzung des/der new operatoren ist wenn man ehrlich ist wenig gelungen. Es gibt genug "Rants" darüber im Internet. Das ist ein fürchterlicher "Hack" und ein Trauerspiel, dass man nach all den Jahrzehnten nicht den Mut hatte diese Krücke durch einen geeigneten Mechanismus zu ersetzen. Woher soll ich denn wissen wie viel Speicherbereich der operator für seine eigenen Verwaltungsdaten belegen möchte? Auch kann ich nicht sagen wie groß denn die Objekte des Arrays sind, wenn man nur eine Größenangabe hat. Zudem ist das auch noch bei jedem Kompiler/Plattform anders. Super. Die Schuld dann auf den User zu schieben ist glaube ich zu einfach gedacht. Anstatt Bjarne Stroustrup mit der Faraday-Medaille zu ehren hätte man ihm lieber mal den Hintern versohlen sollen. Ok, genug getrollt :). Trotzdem danke für eure Hilfe.


  • Mod

    Th69 schrieb:

    Dann aber den richtigen Include benutzen: <new>, s.a. operator new (und nicht darauf hoffen, daß dieser schon irgendwie über <iostream> (oder andere) eingebunden wird).

    <new> ist lediglich notwendig, wenn wir von besonderen Formen dieser Funktionen Gebrauch machen. Tun wir aber nicht.
    Es ist allerdings ein Header notwendig, sonst ist size_t natürlich kein Typ, das dürfte...

    New[] schrieb:

    Im übrigen ist das include sehr wohl notwendig, da man ansonsten folgende Meldung bekäme:

    error: declaration of ‘operator new’ as non-function
    void* operator new(size_t size)

    ... erklären (siehe auch hier). Was wir zu vermitteln versuchen, ist, dass dieser Header die im Program einbezogenen Funktionen gar nicht deklariert. Dafür wären <cstdio> , <cstdlib> und <cstdint> zuständig.

    Woher soll ich denn wissen wie viel Speicherbereich der operator für seine eigenen Verwaltungsdaten belegen möchte?

    Das ist doch die Kernidee: Der new Ausdruck alloziert zwar mehr, als vom Array selbst in Anspruch genommen wird, aber deine allocation/deallocation replacement functions sind einfach für alle Argumente funktional. Wo liegt das Problem?

    New[] schrieb:

    Das ist ein fürchterlicher "Hack" und ein Trauerspiel, dass man nach all den Jahrzehnten nicht den Mut hatte diese Krücke durch einen geeigneten Mechanismus zu ersetzen.

    Es ist kein Trauerspiel. Wenn es ein Problem gibt, für das du keine Lösung findest, setze dich mit dem Komitee in Verbindung. Oder sag's mir, dann diskutieren wir es in der nächsten Sitzung des UK Panels. Bin mir aber nicht sicher, ob es zweckentsprechend wäre, dort deine zwangsneurotischen Ergüsse in formeller Manier zu besprechen.



  • New[] schrieb:

    Woher soll ich denn wissen wie viel Speicherbereich der operator für seine eigenen Verwaltungsdaten belegen möchte?

    Wofür musst du das denn wissen?

    New[] schrieb:

    Auch kann ich nicht sagen wie groß denn die Objekte des Arrays sind, wenn man nur eine Größenangabe hat.

    Wofür musst du das denn wissen?

    Eine allocation function wird vom Compiler aufgerufen, um Speicher zu allokieren. Eine deallocation function wird vom Compiler aufgerufen, um Speicher wieder freizugeben. Dabei geht es immer um rohen Speicher. Zu keinem Zeitpunkt haben diese Funktionen in irgendeiner Form Kontakt mit konkreten Objekten. Etwaig in diesem Speicher später konstruierte Objekte oder zuvor existierende Objekte existieren zum Zeitpunkt da der Speicher allokiert bzw. deallokiert wird noch nicht bzw. nicht mehr. Es gibt noch nichtmal eine Regel die besagt dass jedes new / delete bzw. new[] / delete[] direkt zu einem Aufruf einer allocation/deallocation function führt (zumindest nicht mehr). Zugegeben, der new / delete bzw. new[] / delete[] Kram in C++ ist imo aus heutiger Sicht imo in der Tat nicht besonders gelungen. Sinn machen tut das ganze System dahinter allerdings schon...


Anmelden zum Antworten