Placement new in generic union class



  • Nash26 schrieb:

    1. (...)
      Du hast gesehen das Variant keine struct ist, sondern ein Union?
      Wozu brauch ich dann noch std::aligned_storage ?

    Du hast gelesen dass ich "1) Keine Ahnung. Ich sehe aber keinen Grund aligned_storage nicht zu verwenden." geschrieben habe 😉

    Nash26 schrieb:

    In deinem konkreten Beispiel sehe ich kein Problem mit nicht trivial kopierbaren Objekten.

    Du siehst zusätzlich kein Problem mit nicht trivial kopierbaren Objekten? Oder hast du dich da verschrieben?

    Ich denke ich hab' es schon ausreichend beschrieben.
    Du kannst da mit placement new ein T reinmachen was nicht trivial kopierbar ist.
    Du kannst dann weiterhin das Variant Ding mit dem auto-generierten Ctor kopieren.
    Nur dann ist in der trivial kopierten Kopie natürlich kein T drinnen.
    Demzufolge kannst du es dann auch nicht als T ansprechen.
    Wenn du aber wiederrum mit placement new kopierst, dann sollte es auch OK sein.

    Guck dir z.B. einfach mal die Implementierung von boost::optional an.



  • Ok, und was ist wenn ich folgendes Objekt in die union packe?

    struct alignas(128) Fred
    {
      int i;
    };
    

    Ich denke das sollte dann wirklich Probleme geben, was auch immer das heißen mag? Crash? Langsamer Daten zugriff?

    Ich formuliere meine Frage allgemeiner:

    Was ist die Bedingung dafür, dass ich eine beliebigen Klasse auf diese union (die alle primitive Datentypen beinhaltet) mit placement new abspeichern kann?

    Muss ich den Code auf dein spezielles Variant ändern mit aligned_storage ?
    oder kann ich meine Union weiter verwenden?

    In welchen Kapitel im Standard finde ich dazu eine Information? Unter dem Punkt 9.5 Unions ist jedenfalls nichts.



  • Nash26 schrieb:

    Ok, und was ist wenn ich folgendes Objekt in die union packe?

    struct alignas(128) Fred
    {
      int i;
    };
    

    Ich denke das sollte dann wirklich Probleme geben, was auch immer das heißen mag? Crash? Langsamer Daten zugriff?

    Soweit ich weiss ist alignof > sizeof nicht möglich.
    Würde zumindest nie mit Arrays funktionieren - wie sollte sonst jemals das Alignment des 2. Elements passen?

    Nash26 schrieb:

    Ich formuliere meine Frage allgemeiner:

    Was ist die Bedingung dafür, dass ich eine beliebigen Klasse auf diese union (die alle primitive Datentypen beinhaltet) mit placement new abspeichern kann?

    Muss ich den Code auf dein spezielles Variant ändern mit aligned_storage ?
    oder kann ich meine Union weiter verwenden?

    Du musst vermutlich nicht, aber ich würde es machen. Weil ich mit aligned_storage weiss was ich bekomme, weiss wie man es verwenden muss.

    Und was sind die Bedingungen?
    Na die Grösse muss passen und das Alignment muss passen.

    Ganze einfache Variante: verwende aligned_storage<N, N>::type , wobei du dir N einfach frei aussuchst -- so viel wie du halt maximal für nen char/bool "verschwenden" willst. Dann musst du nur noch die Grösse prüfen, da alignof > sizeof eben nicht geht.

    Nash26 schrieb:

    In welchen Kapitel im Standard finde ich dazu eine Information? Unter dem Punkt 9.5 Unions ist jedenfalls nichts.

    Kann ich dir nicht auswendig sagen. Vermutlich aber verstreut über 100 Paragraphen.



  • Aktuell is meine Bedingung:

    template<typename T>
    using can_place_in_variant = std::integral_constant<bool, sizeof(T) <= sizeof(variant) && 
                                                              alignof(T) == alignof(variant)>;
    

    Primitive datentypen (int, bool) wollte ich halt direkt in der union abspeichern ohne "placement new", da brauch ich mich nicht kompliziert zu casten um den Wert da herauszubekommen und es wird vielleicht auch ein wenig was kosten.



  • alignof(T) == alignof
    alignof(T) <= alignof

    Sieht sonst OK aus.
    Und primitive Typen kannst du auch einfach per gecastetem Zeiger da rein schreiben bzw. wieder rauslesen.


  • Mod

    hustbaer schrieb:

    alignof(T) <= alignof

    alignof(variant) % alignof(T) == 0 ?



  • @Arcoth
    Ich hab in Erinnerung dass als Alignment Requirement eh nur Zweierpotenzen erlaubt sind.
    Von daher sollte der "kleiner" Vergleich ausreichend sein.

    Falls das nicht stimmt muss man natürlich % verwenden, ja.


  • Mod

    Ich hab in Erinnerung dass als Alignment Requirement eh nur Zweierpotenzen erlaubt sind.

    Stimmt natürlich. §3.11/4.
    Das ist echt clever von dir. Leider ist cleverer Code der die Intention nicht ausdrückt.. mMn. allgemein nicht zu empfehlen. Genauso würde ich niemals

    if (a & 2)
    

    schreiben um auszudrücken, dass a eine gerade Ganzzahl ist, nur weil der Standard festlegt, dass nur Ganzzahlrepresentierungen verwendet werden dürfen die derartiges unterstützen.
    Ich möchte mich in Code so ausdrücken dass jeder versteht welcher Gedanke hinter einer Bedingung steht. Und deine Art es zu schreiben impliziert einfach, dass kein weiteres Verhältnis zwischen den Ausrichtungen bestehen muss, als dass die von T kleiner als die von X ist.

    Sag's mir, falls ich übertreibe.



  • Arcoth schrieb:

    Leider ist cleverer Code der die Intention nicht ausdrückt.. mMn. allgemein nicht zu empfehlen.

    Arcoth@unverspielt: 😋
    Hast anscheinend die 15 Jahre, die die meisten dafür brauchen, auf nur 5 drücken können.
    Hoffe, ich hatte mit meiner Meckerei einen kleinen Anteil (vermutlich dadurch, daß Du genau das Gegenteil meiner Wünsche machtest und gegen Wände gelaufen bist).



  • @Arcoth
    Ich verstehe dein Argument.
    Ich weiss nicht ob ich sagen würde dass du übertreibst. Wenn der einzige Nachteil deiner Variante der wäre, dass sie ein klitzekleines bisschen "komplizierter" ist, dann würde ich dir vielleicht zustimmen.

    Nur ... genau so wie meine Variante impliziert dass a <= b ausreicht, und nicht noch die versteckte Bedingung dass a und b beides Zweierpotenzen sein müssen notwendig ist...
    Genau so impliziert deine Variante dass es nötig ist den Test b % a == 0 zu machen, und dass es eben keine weitere Vorschrift vom Standard gibt die einem das Leben hier etwas einfacher macht.

    Wenn ein armer Programmierer das jetzt nicht weiss, und deinen Code liest, und das Programm erweitern muss...
    und dann davon ausgeht dass er überall mit allen möglichen Alignment Requirements rechnen muss...
    und nicht auf die Idee kommt mal im Standard nachzugucken was da wirklich die Regeln sind...
    dann würde er vermutlich viel viel zu komplizierten Code schreiben.

    Was mMn. klar gegen deine Variante spricht.

    Aber Gott-sei-Dank gibt es ja sowas wie Kommentare 🙂
    Vorschlag:

    alignof(T) <= alignof(variant) /* alignment requirements are always a power of two, so checking a <= b is sufficient */
    

    oder, wenn du unbedingt willst

    alignof(variant) % alignof(T) == 0 /* actually alignment requirements are always a power of two,
                                          so b <= a would suffice, but a % b == 0 more clearly expresses what we are really testing here */
    

    Wobei ich auch hier die a <= b Variante vorziehe, weil sie den Fokus auf die einfachere, ausreichende Variante setzt.

    ps:

    Arcoth schrieb:

    Stimmt natürlich. §3.11/4.
    Das ist echt clever von dir.

    Gar nicht clever, ich kenne es einfach nicht anders. Also jeglicher Code den ich bisher gesehen habe der Alignment Requirements prüft verwendet einfach a <= b Tests.
    BTW: Nachdem sich bei C++ in den letzten Jahren einiges getan hat, und auch hoffentlich weiterhin was tut, und so viel tut dass sich die ganzen §-Nummern im Standard gröber verschieben, wäre es vielleicht günstig immer die Standard-Version mit anzugeben.
    Also entweder die "n-Nummer" oder einfach "C++XY".

    EDIT: Fixed: a < b --> a <= b



  • volkard schrieb:

    Hast anscheinend die 15 Jahre, die die meisten dafür brauchen, auf nur 5 drücken können.

    Ich finde die Entwicklung von HaSoCoth ... erstaunlich. Ernsthaft. 👍@Arcoth


  • Mod

    volkard schrieb:

    Hast anscheinend die 15 Jahre, die die meisten dafür brauchen, auf nur 5 drücken können.

    Vier 🙂



  • Arcoth schrieb:

    Genauso würde ich niemals

    if (a & 2)
    

    schreiben um auszudrücken, dass a eine gerade Ganzzahl ist, nur weil der Standard festlegt, dass nur Ganzzahlrepresentierungen verwendet werden dürfen die derartiges unterstützen.

    würde ich auch nicht, aber aus einem anderen Grund.
    (Tip: !(a&1))


  • Mod

    Wenn ein armer Programmierer das jetzt nicht weiss, und deinen Code liest, und das Programm erweitern muss...
    und dann davon ausgeht dass er überall mit allen möglichen Alignment Requirements rechnen muss...

    Bin nicht dran gewohnt oder ausgerichtet mit Leuten zu arbeiten, die unbegründete Annahmen aus einer Code-Zeile entnehmen und auf dieser Basis ein Projekt erweitern/umschreiben.

    großbuchstaben schrieb:

    würde ich auch nicht, aber aus einem anderen Grund.
    (Tip: !(a&1))

    Ups, da war ich im Eifer des Gefechts ganz woanders, sorry. Es hilft nicht, dass ich gerade mit etwas völlig anderem Beschäftigt bin.

    hustbaer schrieb:

    volkard schrieb:

    Hast anscheinend die 15 Jahre, die die meisten dafür brauchen, auf nur 5 drücken können.

    Ich finde die Entwicklung von HaSoCoth ... erstaunlich. Ernsthaft. 👍@Arcoth

    Klingt zynisch. Und da ich annehmen darf, dass ein Gentlemen wie du nicht aus Versehen zynisch ist...



  • Daran war nichts zynisch gemeint.
    Du musst ja auch selbst merken wie sich z.B. der Ton mit dem wir uns unterhalten MASSIV verbesser hat in den letzten Jahren.

    ps: Falls du dich am "HaSoCoth" gestossen hast - das war nicht böse gemeint. Der kleine Insiderwitz sei mir bitte verziehen 🙂



  • Arcoth schrieb:

    Wenn ein armer Programmierer das jetzt nicht weiss, und deinen Code liest, und das Programm erweitern muss...
    und dann davon ausgeht dass er überall mit allen möglichen Alignment Requirements rechnen muss...

    Bin nicht dran gewohnt oder ausgerichtet mit Leuten zu arbeiten, die unbegründete Annahmen aus einer Code-Zeile entnehmen und auf dieser Basis ein Projekt erweitern/umschreiben.

    Das selbe Argument funktioniert auch für den Standpunkt dass deine Variante unnötig kompliziert ist, und auch ein einfaches a <= b ohne weiteres Kommentar völlig ausreicht.

    Wenn ich deinen Code - ohne weiteres Kommentar - irgendwo lesen würde, dann würde es mich kurz verwirren. Und danach würde ich mir denken "weiss der nicht dass a <= b reicht, oder macht er Dinge einfach gerne unnötig kompliziert?".



  • hustbaer schrieb:

    alignof(T) == alignof
    alignof(T) <= alignof

    Sieht sonst OK aus.
    Und primitive Typen kannst du auch einfach per gecastetem Zeiger da rein schreiben bzw. wieder rauslesen.

    Wie kann ich einen Wert (double, und custom type) in einem std::aligned_storage
    speichern und wieder rausholen?



  • struct Foo
    {
        template <class T> void put_trivial(T t)
        {
            *reinterpret_cast<T*>(&m_storage) = t;
        }
    
        template <class T> T get_trivial() const
        {
            return *reinterpret_cast<T const*>(&m_storage);
        }
    
        std::aligned_storage<...>::type m_storage;
    };
    

    Und nicht triviale Typen dann entsprechend mit placement new , bzw. nach dem das Objekt einmal erstellt ist kannst du genau so den reinterpret_cast<T*> verwenden um an einen gültigen T* Zeiger zu kommen.



  • Also ich hab inzwischen sowas hier:

    struct Foo
    {
        template <class T> void put_trivial(T t)
        {
            reinterpret_cast<T&>(m_storage) = t;
        }
    
        template <class T> T get_trivial() const
        {
            return reinterpret_cast<T const&>(m_storage);
        }
    
        std::aligned_storage<...>::type m_storage;
    };
    

    und für Pointer:

    struct Foo
    {
        template <class T> void put_trivial(T* t)
        {
            reinterpret_cast<T*&>(m_storage) = t;
        }
    
        template <class T> T* get_trivial() const
        {
            return reinterpret_cast<T const*&>(m_storage);
        }
    
        std::aligned_storage<...>::type m_storage;
    };
    

    Das ist doch auch okay, oder?



  • Ne. Ka. was das darstellen soll.

    ps: Wenn du davon so überhaupt keinen Plan hast, wäre es dann nicht besser du suchst dir ne andere Beschäftigung?


Anmelden zum Antworten