realloc 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^^



  • @Wade1234 sagte in realloc C++:

    @unskilled sagte in realloc C++:

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

    Ja gut.... dazu fällt mir dann nicht mehr all zu viel ein. Wenn man nie Auto-Fahren gelernt hat und es nicht lernen will, dann sollte man es eigentlich lassen, weil andernfalls zuviele Unfälle passieren.



  • @wob sagte in realloc C++:

    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.

    Danke, genau danach hab ich ja gefragt 🙂
    Offenbar finden die auch keine bessere Definition, als die beiden Ausnahmen anzuführen^^

    @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.

    Weil ich es nun mal für C++ wissen wollte. Irgendwie ist die Funktion ja auch Teil des C++ Standards.
    Aber schön zu wissen, dass sich in den letzten Jahren nichts an den Antworten geändert hat. Selbst wenn ich explizit im ersten Post schreibe, dass ich das wissen möchte, sind die Hälfte der Antworten völlig am Thema vorbei...

    Hier nen relativ interessanter Thread dazu
    https://stackoverflow.com/questions/29777492/why-would-the-behavior-of-stdmemcpy-be-undefined-for-objects-that-are-not-triv

    Und einer mit einer schönen Zusammenfassung:
    https://stackoverflow.com/questions/39026871/can-i-use-memcpy-to-write-to-multiple-adjacent-standard-layout-sub-objects

    In the example, the three members comprise a "trivially copyable sub-object", and indeed I think wrapping them in an actual subobject of distinct type would still mandate exactly the same memory layout for the explicit object as for the three members:

    [...]

    • have a very, very hard time imagining an implementation or optimizer that breaks this

    Would say it either can be:

    • read as Undefined Behavior, iff we conclude that C++§3.9/3 implies that only (full) objects of Trivially Copyable Type are allowed to be be treated thusly by memcpy or conclude from C99§6.2.6.1/2 and the general spec of memcpy 7.21.2.1 that the contiguous sequence of the num_* bytes does not comprise a "valid object" for the purposes of memcopy.

    • read as Defined Behavior, iff we conclude that C++§3.9/3 does not normatively limit the applicability of memcpy to other types or memory ranges and conclude that the definition of memcpy (and the "object term") in the C99 Standard allows to treat adjacent variables as a single object contiguous bytes target.

    @andere Mutmaßungen wie Exceptions auf µCtrl oder das Auto fahren werde ich mal versuchen zu ignorieren.


Anmelden zum Antworten