new und realloc



  • das heißt wenn ich mit objekten arbeite, sollte ich immer mit new arbeiten, damit die konstruktoren etc. richtig abgearbeitet werden?



  • Da new indirekt malloc aufruft kann man im prinzip das schon mischen.
    Aber nur wenn man keine klassen verwendet. Denn bei malloc wird einfach nur der benötigte speicher für das "Objekt" geholt.
    Was aber bei einer Klasse schlecht ist, wenn diese auch dynamische Daten-member enthält.
    new dagegen ruft nach dem Holen des Speichers für das "Objekt" den Konstruktor (wenn es sich um eine klasse handelt) auf.

    Also im prinzip geht das schon nur ist das ganze unschön. Und kann eventuell auch zu fehlern, bei der Ausführung des Programms führen.

    realloc funktioniert in etwa so (laut der implementation gefunden in der glibc):
    funktion: void* realloc(void* ptr, size_t size)

    • wenn ptr = NULL dann funktioniert realloc wie malloc.
    • wenn ptr != NULL:
    • wenn size <= der Größe des Speicherblocks auf den ptr zeigt:
    • size == Größe des Speicherblocks von ptr -> ptr wird wieder zurückgegeben.
    • size < Größe des Speicherblocks von ptr -> ptr wird wieder zurückgegeben. Der restliche speicher wird wieder freigegeben.
    • wenn size > der Größe des Speicherblocks auf den ptr zeigt:
    • neuer speicher der größe size wird erstellt und der inhalt von ptr wird in den neuen bereich kopiert.


  • FreakyBKA schrieb:

    das heißt wenn ich mit objekten arbeite, sollte ich immer mit new arbeiten, damit die konstruktoren etc. richtig abgearbeitet werden?

    so isses, dann fühlt sich c++ am wohlsten. bei malloc müssteste den konstruktor irgendwie manuell starten. ich würde sowas lieber lassen...
    :xmas2:

    ss schrieb:

    Da new indirekt malloc aufruft kann man im prinzip das schon mischen.

    nö, im prinzip *nicht*



  • ten schrieb:

    FreakyBKA schrieb:

    das heißt wenn ich mit objekten arbeite, sollte ich immer mit new arbeiten, damit die konstruktoren etc. richtig abgearbeitet werden?

    so isses, dann fühlt sich c++ am wohlsten. bei malloc müssteste den konstruktor irgendwie manuell starten. ich würde sowas lieber lassen...
    :xmas2:

    ss schrieb:

    Da new indirekt malloc aufruft kann man im prinzip das schon mischen.

    nö, im prinzip *nicht*

    doch schon 😉 habs selbst getestet 😉 aber wie ich und andere schon geschrieben haben funktioniert das aber nur mit nicht klassen-objekten. Und es kann zu laufzeit problemen führen.

    In welcher weise sollte sich das verhalten von malloc und new denn noch unterscheiden auser dem punkt mit dem aufrufen des Konstruktors bei klassen-objekten?

    Ich habe gerade in den sourcen von gcc nachgeschaut: und da wird bei dem new-operator malloc aufgerufen um den eigentlichen Speicher zu reservieren.



  • ss schrieb:

    doch schon 😉 habs selbst getestet 😉

    Im Standard ist trotzdem nicht festgelegt, dass Operator new malloc aufruft. Insofern kann eine Implementation das handhaben, wie sie will. Daher ist es einfach ungesund new/delete und malloc/free zu vermischen. Wie deine Implementation das macht, ist deshalb relativ belanglos.



  • Seine Implementation?
    g++ ist ja wohl der mit Abstand meistverwendete C++ - Compiler in der Unixwelt.



  • Was an groovemasters Aussage exakt nichts ändert.



  • Hätte ich nie behauptet.



  • AFAIK kann man doch new überschreiben. Und ich glaube man kann es auch so überschreiben, dass man angeben kann, wo das Objekt erstellt werden soll. D.h. man könnte dann den Array-Speicher mittels realloc vergrößern und das neue Objekt mit dem überschriebenen new auf dem Speicher anlegen.
    Allerdings ist das gefährlich wenn ein Objekt z.B. seinen this-Zeiger als mem-var speichert (oder sonstwas).
    Das beste für ein (selbstgemachtes) Array für Klassen ist IMO, ein Array von Zeigern mit malloc/realloc/free zu verwalten, welche auf die Objekte zeigen. Das dürfte std::vector aber wahrscheinlich auch so machen 🙂



  • das mit den array von zeigern ist auch keine schlechte idee, werde ich wohl dann mal so probieren.
    aber mal ne andere frage, woher weiß realloc eigentlich wie groß mein übergebenes feld ist, die funktion bekommt ja nur den zeiger und die neue größe als parameter. das heißt es muss dann irgendwie im speicher eine bestimmte codierung geben die mir sagt hier ist das array zu ende. dann stell ich mir aber die frage was passiert wenn ich in meinem aktuellen array an einer stelle diese codierung reinschreibe und dann realloc aufrufe.
    kann mir vllt jemand erklären wie genau das geregelt ist. danke schonmal im voraus.



  • FreakyBKA schrieb:

    ...woher weiß realloc eigentlich wie groß mein übergebenes feld ist, ...
    kann mir vllt jemand erklären wie genau das geregelt ist. danke schonmal im voraus.

    Soweit ich weiß, ist das überhaupt nicht "geregelt" ... das kann eine konkrete runtime-Implementation machen, wie sie will. .. Trifft übrigens auf free ebenso zu: "Irgendwo im System" hinterlegt malloc(), wie viel Speicher es für diesen Pointer alloziert hat ... und dort rufen es free(), realloc() & Co dann ab.

    Gruß,

    Simon2.



  • das wird dann bei new und delete wohl ganz ähnlich sein. wenn ich mir dann jetz für objektfelder die ich mit new erstellt habe ein funktion wie realloc(), halt nur für new zB. renew(), schreibe muss ich der funktionen den zeiger auf das alte feld, die alte größe und die neue größe übergeben. die alte größe brauch ich ja dann um das alte feld zwischenzuspeichern. wenn die alte feldgröße vom benutzer eingegeben wird kann man dann doch aber sicherlich ziemlich viel blödsinn mit anstellen, wenn ich mein feld als größer angebe als es eigentlich war. ich habs schon mit kleinen feldern ausprobiert und es funktioniert, ich konnte sogar den inhalt von speicherplatz, den ich gar nicht alloziert habe ändern, was ich sehr bedenklich finde.



  • Simon2 schrieb:

    das kann eine konkrete runtime-Implementation machen, wie sie will. .. Trifft übrigens auf free ebenso zu: "Irgendwo im System" hinterlegt malloc(), wie viel Speicher es für diesen Pointer alloziert hat ... und dort rufen es free(), realloc() & Co dann ab.

    oft basieren heaps auf verketteten listen und diese informationen stehen oft direkt vor dem speicherblock den man gemalloct hat. z.b da:

    int *m = malloc(100);
    struct block_info *info = (struct block_info*)((char*)m)-sizeof(struct block_info);
    

    ab da man als normaler c/c++ user diese struktur nicht kennt und weil's sowieso 'implementation-defined' ist, kann man's nicht verwerten...
    :xmas2:



  • OK im standard steht nicht drinn das der new-operator intern malloc/calloc/realloc aufrufen muss aber es steht da auch nicht drinn, das dies verboten sei.
    Sprich die wahl ob malloc oder eine neuimplementation der Speicherreservierungs-algo verwendet wird kann der Compiler-/c++-Runtime entwickler selbst entscheiden.

    aus http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf seite 401:

    void * operator new(std :: size_t size ) throw (std :: bad_alloc );
    1 Effects:The allocation function (3.7.3.1) called by a new-expression (5.3.4) to allocate size bytes of storage
    suitably aligned to represent any object of that size.
    2 Replaceable: a C++ program may define a function with this function signature that displaces the default version
    defined by the C++ Standard library.
    3 Required behavior: Return a non-null pointer to suitably aligned storage (3.7.3), or else throw a bad_alloc
    exception. This requirement is binding on a replacement version of this function.
    4 Default behavior:
    — Executes a loop: Within the loop, the function first attempts to allocate the requested storage. Whether the
    attempt involves a call to the Standard C library function malloc is unspecified.

    Die Verwendung von malloc in der implementation von new ist in der hinsicht sinnvoll, da man dadurch code-duplication vermeiden kann.

    Desweiteren muss man nicht auch noch den new-operator reimplemntieren, wenn man die c- und die c++ Runtime/Compiler auf eine neues Betriebsystem/neue Architektur portiert, wo sich das Memory-Management eventuell anders verhält/aufgebaut ist.

    ich(ich bin ss, da ich bisher zu faul war mich einzuloggen ;)) habe aber immer darauf hingewiesen, das man malloc und new nicht mischen sollte. Ich habe nur gesagt, das es im prinzip geht und nicht gesagt das man das tun soll.

    Und ich konnte meine Behauptung, das new indirekt malloc aufruft auch beweisen(zumindestens in der implementation vom gcc-projekt)



  • firefly schrieb:

    Und ich konnte meine Behauptung, das new indirekt malloc aufruft auch beweisen(zumindestens in der implementation vom gcc-projekt)

    Wir programmieren aber nicht für einen konkrete Compiler bzw. eine konkrete Implementation, sondern wollen so portabel wie möglich bleiben. Und da interessiert es einfach nicht, was GCC hier macht. Zumal die Möglichkeit besteht, dass sich die Implementation von new/delete in späteren Versionen des GCC ändern könnte.



  • Wenn du mit malloc oder realloc den Speicher holst, kannst du die Größe mit _msize holen. Müsste eigentlich immer konform sein...



  • Badestrand schrieb:

    Wenn du mit malloc oder realloc den Speicher holst, kannst du die Größe mit _msize holen. Müsste eigentlich immer konform sein...

    ich glaub' _msize gibt's nur bei mickrigsoft und steht nicht in der c oder c++ spec.
    :xmas2:



  • d.h. wenn ich einen zeiger ptr habe bekomme ich mit _msize(ptr) die größe des allozierten speichers? ist das dann die feldgröße oder muss ich dann noch durch sizeof(typ) dividieren um meine feldgröße zubekommen? die frage ist dann noch ob es dieses _msize() überall gibt.



  • FreakyBKA schrieb:

    die frage ist dann noch ob es dieses _msize() überall gibt.

    die frage ist, ob du mit aller gewalt plattformunabhängig coden willst 😉
    :xmas2:



  • FreakyBKA schrieb:

    die frage ist dann noch ob es dieses _msize() überall gibt.

    Nein. Deshalb, merk dir die Grösse. Oder verwende einen passenden Container, der das für dich macht. Bequemer geht's nicht. Speicherverwaltung sollte kein primäres Aufgabengebiet eines Entwicklers sein.


Anmelden zum Antworten