realloc C++



  • Moin.

    Zu erst: Bitte keine Standard-Antworten á la nimm doch std::vector, oder brauchst du nicht. Auch kein nimm new[] / new mit placement new, Destruktor und delete[] / delete etc.
    Danke.

    Ich beschäftige mich gerade mit Mikro-Controllern und somit ist Speicher jeder Art sowie nutzbare Bibliothek sehr stark begrenzt. Wir gehen einfach mal davon aus, dass realloc mehr als stumpfes malloc, memmove und free ist und es somit Sinn macht zumindest darüber nachzudenken. Abgesehen davon gibt es ja mit container::shrink_to_fit mittlerweile auch ein tatsächlich sinnvolles Argument für realloc.

    Es gibt also den C++ Weg mit:

    • std::vector

    ...den (C++-artigeren C-) Weg mit:

    • new[], placement new, CopyCTor, DTor und delete[]

    ...den (C-artigen C++-) Weg mit:

    • ::malloc, placement new, CopyCTor, DTor und ::free

    und nun das Gleiche auch noch mit realloc:

    • ::realloc (->memmove statt CopyCTor), placement new, Dtor und ::free

    ...um Objekte mittels Array zu verwalten.

    Kann man (z.B. mit static_assert) ausdrücken, welche Voraussetzungen die Klasse erfüllen muss, damit alles "well defined" ist?

    Ehrlich gesagt fällt mir nicht mal eine verbale Definition ein, um zu sagen, wann es geht sondern nur eine Aufzählung von Beispielen, in denen es nicht funktionieren würde: wenn die Klasse sich selbst irgendwo registrieren muss; also alles Richtung observer pattern.
    Im Prinzip läuft es vermutlich auf ein 'einfach' swappable hinaus. Einfach nicht umsonst in Anführungszeichen.

    Dass ::realloc kein guter (da nicht allgemeingültiger) Weg in C++ ist, ist mir also klar. Das ist hier aber nicht das Thema.

    Und nochmal am Schluss da ich noch weiß, wie solche Threads damals stets verliefen: Es geht nicht um memcpy sondern ausschließlich um memmove.



  • und was hast du jetzt vor? warum benutzt du eigentlich kein C?



  • @unskilled sagte in realloc C++:

    Es geht nicht um memcpy sondern ausschließlich um memmove.

    Die Voraussetzungen bezüglich des Datentyps sind aber gleich: TriviallyCopyable



  • @Wade1234
    Die Frage war
    "Kann man (z.B. mit static_assert) ausdrücken, welche Voraussetzungen die Klasse erfüllen muss, damit alles "well defined" ist?"
    Ich habe mir nen vector-clon samt realloc-fähigem allocator gebaut.
    C benutze ich nicht, weil zu wenig Ahnung und zu faul was neues zu lernen^^

    @manni66
    Also ich seh nicht, wo das vorausgesetzt wird.
    Ich sehe nur, dass ein Ergebnis von 2x memcpy (unter bestimmten voraussetzungen) garantiert wird und als kommentar dazu steht, dass das gleiche auch für memmove gilt.

    Das hier finde ich:
    6.9. Types
    ( 4 ) The object representation of an object of type T is the sequence of N unsigned char objects taken up by the
    object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that
    hold the value of type T.

    Ich bin mir fast sicher, dass man zusammen mit dem C-Standard und den garantierten Ergebnissen ne Menge bzgl memmove garantieren kann.
    struct foo{ char* str; unsigned len };
    darf man zweifelsohne mem-moven.

    das hier:
    struct bar{ bar(const bar&) {} char* str; unsigned len };
    bestimmt auch. nur ist das ergebnis nicht garantiert, weil nicht allgemeingültig formulierbar



  • @unskilled sagte in realloc C++:

    @manni66
    Also ich seh nicht, wo das vorausgesetzt wird.

    https://en.cppreference.com/w/cpp/string/byte/memcpy

    Aus dem Standard klamüser ich das nicht raus, aber 6.9 (2) sagt da ja auch noch was.

    @unskilled sagte in realloc C++:

    nur ist das ergebnis nicht garantiert

    Was genau verstehst du unter "ist erlaubt"?



  • 6.9.2
    For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object
    holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array
    of char or unsigned char.
    If the content of the array of char or unsigned char is copied back into the
    object, the object shall subsequently hold its original value

    aber die frage war ja nicht, was alles garantiert ist, wenns trivial zu kopieren ist...

    "Was genau verstehst du unter "ist erlaubt" "
    das memmove das macht, was es soll: und zwar sizeof(T) an memory moven. und die neue stelle als "normales" T zu interpretieren.

    jetzt war meine frage, ob man beschreiben kann, was T nicht können darf (oder können muss), damit sizeof(T) auch ("richtig") als T interpretiert werden kann.
    das sollte auf so etwas hinauslaufen, wie a) darf nicht auf sich selbst zeigen b) muss seine adresse nirgendwo registrieren (was streng genommen a) einschließt).

    dass bei is_trivially_copyable immer und alles gut geht, ist schon klar.



  • Ich habe damit auch mal experimentiert und bin damals zu dem Schluss gekommen, dass man die Unterstützung des Speichermanagers benötigt, wenn man das effizient und korrekt für beliebige Typen umsetzen will - also jenseits von TriviallyCopyable.

    Das Problem ist, dass man nicht bereits vor dem Aufruf von realloc weiss, ob der Speicherbereich erfolgreich vergrößert/verkleinert werden kann. Ist man sicher, dass realloc kein memmove durchführt, könnte man die Objekte einfach unangetastet im Speicher lassen und nur für die Objekte, die rausfallen/neu hinzukommen entsprechend die Destruktoren und Konstruktorn aufrufen. Ansonsten macht man eben ein "C++-Move" in die default-konstruierten Objekte des neuen Speicherbereichs.

    So etwas wie ein try_realloc wäre da hilfreich, dass einfach fehlschlägt, wenn ein memmove notwendig ist. Das gute alte realloc macht da einfach zuviel. nedmalloc z.B. hat eine solche Funktion (realloc2 unterstützt dort ein Flag, mit dem sich das memmove deaktivieren lässt), andere Speichermanger eventuell auch. Wenn man es wirklich wissen will, kann man es damit mal versuchen, natürlich nagelt man sich dann auf eine malloc-Implementierung fest.

    Schade, dass es dafür keine portable Lösung gibt. Ich kann mir vorstellen, dass das bei den meisten realloc-Implementierungen trivial umzusetzen wäre - denke die machen so ziemlich alle unter der Haube eh nur ein malloc/memmove wenn das interne realloc fehlschlägt.



  • @Wade1234 sagte in realloc C++:

    warum benutzt du eigentlich kein C?

    Welchen Vorteil hat C, wenn man C++ kann und ein C++-Compiler für die Zielplattform verfügbar ist?



  • @Finnegan sagte in realloc C++:

    Ich habe damit auch mal experimentiert und bin damals zu dem Schluss gekommen, dass man die Unterstützung des Speichermanagers benötigt, wenn man das effizient und korrekt für beliebige Typen umsetzen will - also jenseits von TriviallyCopyable.
    ...

    Jo; das wäre natürlich super einfach. Aber mir ging es ja darum, dass ich weiß, wie meine Objekte aussehen weil ich der bin, der den Anwendercode schreibt und damit (fast - wie das eben ist, falls es wirklich UB sein sollte) sicher bin, dass trotz memmove nix kaputt geht.
    Es geht halt um nen eigenen string ohne small-string-optimization weil mir taktzyklen völlig egal sind; nur eben der speicher potentiell knapp ist. also 2x unsigned 1x char*. d.h. auch das umkopieren wäre völlig vernachlässigbar. nicht aber die tatsache, dass ich kurzzeitig mal 2 bis 3mal so viel speicher anforder wie ich eigentlich benötigen würde. außerdem ist es halt super fix geschrieben - und sogar das shrink_to_fit funktioniert (und das vrmtl auch ohne umkopieren)...

    die (vermutlich gar nicht so dumme) alternative wäre wohl nen eigener allocator, der einfach (fast) alles am reserviert und selbst was realloc-mäßiges anbietet. das sieht aber recht schnell recht hässlich im quellcode aus (alloc überall rumreichen). Und hat wieder nen overhead. Wäre aber vom Lerneffekt und den Möglichkeiten her sicher am coolsten.
    Oder man missbraucht und überlädt das placement new dafür.
    Da fallen mir persönlich schon viele Möglichkeiten ein. Aber ohne Erfahrung kann ich da nicht beurteilen, was der beste Weg wäre.

    Sei es, wie es wolle - ich habe mich "damals" für den C++ Weg entschieden und muss nun damit leben.
    Deshalb wollte ich jetzt jemanden, der sagt "ja, memmove wird auf jeder plattform das machen, was du erwartest. das geht aus dem c standard §drölf hervor zusammen mit abwärts-kompatibilität. daraus wird auch immer ein object eines beliebigen T's. Ob das invariant ist, kommt wie du festgestellt drauf an. Da ich mich auskenne, kann ich sagen, dass es immer gut geht, wenn ...".

    @Finnegan

    Welchen Vorteil hat C, wenn man C++ kann und ein C++-Compiler für die Zielplattform verfügbar ist?

    Na der Vorteil liegt auf der Hand: Ich wüsste zweifelsohne, dass memmove wohl definiert ist (in C ist es das auf struct foo von oben). Aber mir persönlich ist da RAII zu viel wert.

    Also zurück zur Frage:
    Ist memmove aus der C++ standard lib auf ein nicht-trivial-kopierbares objekt UB? (Das Problem an der Frage ist natürlich offensichtlich: Jeder kann erst mal ja! sagen, bis dann jemand kommt und sagt "Nein, schaut: ...")
    Oder ist nur UB, was danach herauskommt? (T(old_mem) != T(new_mem))
    Oder (und?) ist das beides "[praktisch] well formed"?
    Oder ist es immer well formed; abgesehen davon, dass das neue Objekt eben Invarianz hervorrufen kann?



  • @unskilled

    Ist memmove aus der C++ standard lib auf ein nicht-trivial-kopierbares objekt UB?

    Laut cppreference: ja!

    Ein char ist trivial kopierbar. Wo ist das Problem?


  • Gesperrt

    @Finnegan sagte in realloc C++:

    Welchen Vorteil hat C, wenn man C++ kann und ein C++-Compiler für die Zielplattform verfügbar ist?

    Den Vorteil, dass man sich nicht über unnötige Abstraktionen den Kopf zerbricht, sondern einfach memmove() oder memcpy() anwendet.



  • @unskilled sagte in realloc C++:

    Ist memmove aus der C++ standard lib auf ein nicht-trivial-kopierbares objekt UB? (Das Problem an der Frage ist natürlich offensichtlich: Jeder kann erst mal ja! sagen, bis dann jemand kommt und sagt "Nein, schaut: ...")

    Alles was der Standard nicht definiert ist undefined-behaviour.

    [class.prop]/1
    [basic.types]/3

    Mehr geht ned.



  • @Finnegan sagte in realloc C++:

    Welchen Vorteil hat C, wenn man C++ kann und ein C++-Compiler für die Zielplattform verfügbar ist?

    C ist schlank und einfach gehalten. ich meine, wir reden hier von mikrocontrollern, da braucht man keine oop.

    welchen vorteil hat C++ denn? class Pin1:Pin? throw PinNotConnectedException? den ganzen kram braucht auf der ebene doch kein mensch! wahrscheinlich brauchst du da nicht mal realloc, weil du direkt in den speicher schreiben kannst bzw. gar keine speicherverwaltung vorhanden ist.

    C++ löst probleme, die man ohne C++ gar nicht hätte, oder wie war das?



  • @Wade1234 sagte in realloc C++:

    C++ löst probleme, die man ohne C++ gar nicht hätte, oder wie war das?

    Auf Mikrocontrollerebene gebe ich dir Recht. Da ist C++ im Grunde unnötig, aber dort baut man auch keine riesen Projekte.
    Bei großen Softwareprojekten wirst du mit C ne ganze Menge mehr Aufwand haben als mit C++.



  • @RBS2, @Wade1234 Trollt euch doch bitte mit euren Privatmeinungen aus C++-Threads. Nach einer Entscheidungshilfe bei einer Sprachenwahl hat hier niemand gefragt.



  • @It0101 sagte in realloc C++:

    Auf Mikrocontrollerebene gebe ich dir Recht. Da ist C++ im Grunde unnötig, aber dort baut man auch keine riesen Projekte.

    und genau darum gehts doch:
    @unskilled sagte in realloc C++:

    Ich beschäftige mich gerade mit Mikro-Controllern und somit ist Speicher jeder Art sowie nutzbare Bibliothek sehr stark begrenzt.

    @Swordfish sagte in realloc C++:

    @RBS2, @Wade1234 Trollt euch doch bitte mit euren Privatmeinungen aus C++-Threads. Nach einer Entscheidungshilfe bei einer Sprachenwahl hat hier niemand gefragt.

    ja das ist wohl am besten so.🙄



  • @unskilled Im aktuellen C++ Standard gibt es dazu schlicht und ergreifend nix brauchbares. Dinge die in diese Richtung gehen (Traits ala "is-memcpy-relocatable" oder "is-trivially-relocatable") werden AFAIK aktuell diskutiert, aber geben tut's sie halt noch nicht.



  • Das relocatable-Problem haben auch schon andere erkannt. In Facebooks vector-Ersatz folly::fbvector muss man einen Typ mit einem IsRelocateable-Trait markieren. Siehe https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md#object-relocation.

    Wäre schön, wenn man dem std::vector sowas beibringen könnte.



  • @Wade1234 sagte in realloc C++:

    @It0101 sagte in realloc C++:

    Auf Mikrocontrollerebene gebe ich dir Recht. Da ist C++ im Grunde unnötig, aber dort baut man auch keine riesen Projekte.

    und genau darum gehts doch:
    @unskilled sagte in realloc C++:

    Ich beschäftige mich gerade mit Mikro-Controllern und somit ist Speicher jeder Art sowie nutzbare Bibliothek sehr stark begrenzt.

    Warum ist der Thread dann im C++-Forum und nicht im C-Forum? Der Verdacht drängt sich mir auf, dass hier Schlamperei-Mischmasch betrieben werden soll.



  • @It0101 sagte in realloc C++:

    Warum ist der Thread dann im C++-Forum und nicht im C-Forum? Der Verdacht drängt sich mir auf, dass hier Schlamperei-Mischmasch betrieben werden soll.

    diesen verdacht hatte ich auch und genau das war auch der grund, weshalb ich so doof gefragt habe, warum kein C verwendet werden soll. die antwort habe ich ja auch bekommen:

    @unskilled sagte in realloc C++:

    C benutze ich nicht, weil zu wenig Ahnung und zu faul was neues zu lernen^^


Anmelden zum Antworten