Union mit struct initialisieren



  • Hallo, ich komme bei folgenden Problem nicht weiter und hoffe mir kann jemand helfen. Wenn ich ein Union habe, dass ein struct beinhaltet, wie schaff ich dann ein neues Union-Objekt und initialisiere dieses?

    Hier ein Beispiel:

    #include <iostream>
    
    union Literal {
      struct meta_ {
        uint32_t lit;
        uint32_t lvl;
        meta_( void ) : lit(0), lvl(0) {}
        meta_( const uint32_t& literal, const uint32_t& level  ) : lit(literal),   
        lvl(level) {}
      } meta;
      uint64_t data;
    };
    

    Vielen Dank für eure Antworten.



  • Das geht mit Hilfe eines "placement new" oder mit direkter Initialisierung.
    Also z.B.

    // placement new:
    Literal() { new (&meta) meta(); }
    // oder alternativ, wenn eh klar ist, dass du meta initialisieren willst:
    Literal() : meta_() {}
    

    Den korrekten Destruktor musst du selbst aufrufen. Ich würde davon abraten, "nicht-einfache" Typen in eine Union zu tun.



  • mist, der Unterstrich fehlt:

    Literal() { new (&meta) meta_(); }
    


  • grrr. ich sollte mich doch mal registrieren. Der Unterstrich bei

    Literal() : meta_() {}
    

    ist auch falsch.

    Ich hasse Typnamen, die mit _ enden. Argh.

    Jedenfalls ist obiger Code modulo Unterstriche korrekt. Hoffe ich jedenfalls. Wenn ich nicht noch mehr übersehen habe.



  • Vielen Dank für deine Antwort.
    Leider bekomm ich immer noch Fehlermeldungen bei beiden Versionen.

    g++ -std=c++11 -c arrayMain.cpp
    arrayMain.cpp: In function ‘int main(int, char**)’:
    arrayMain.cpp:17:9: error: use of deleted function ‘main(int, char**)::Literal::Literal()’
    Literal() { new (&meta) meta_(); }
    ^
    arrayMain.cpp:7:7: note: ‘main(int, char**)::Literal::Literal()’ is implicitly deleted because the default definition would be ill-formed:
    union Literal {
    ^
    arrayMain.cpp:13:5: error: union member ‘main(int, char**)::Literal::meta’ with non-trivial ‘main(int, char**)::Literal::meta_::meta_()’
    } meta;
    ^
    arrayMain.cpp:17:11: error: expected ‘;’ before ‘{’ token
    Literal() { new (&meta) meta_(); }
    ^
    make: *** [arrayMain.o] Fehler 1

    Müsste ich nicht ide Member des Struct gleich initialisieren, wenn ich das Union-Object erschaffe?


  • Mod

    Wie sieht der vollständige Code aus?



  • Hast du den Literal-Konstruktor auch innerhalb der union hingeschrieben? Scheint mir so, als als hättest du den nur irgendwo dahinter geschrieben.



  • Den ganzen Code kann ich leider nicht schicken. Ist nicht meiner. Mir gehts aber auch mehr ums Prinzip. Ich hab jetzt noch mal einen einfacheren Code hergenommen, um das Prinzip zu kapieren.

    #include <iostream>
    
    int main(int argc, char** argv) {
    
    union myColour {
    struct meta_{
    unsigned int a, b, c, d;
    } meta;
    unsigned int abcd;
    };
    
    myColour test; // das funtioniert
    myColour() : meta_() {1. 2, 3, 5}; //das funktioniert nicht
    std::cout << test.abcd << test.abcd;
    

    Hier klappt es nun zumindest ein myColour-Object namens test zu erschaffen. (Mehr als beim anderen Code). Auch der int abcd kann ich Werte zuweisen. Aber ich schaff es nicht dem struct meta_ Werte zuzuweisen und diese abzurufen.



  • Wie ich es vermutet hatte. Der Konstruktor muss IN der Union deklariert sein!

    #include <iostream>
    
    union Literal {
        struct meta_ {
            uint32_t lit;
            uint32_t lvl;
            meta_(void) : lit(0), lvl(0) {}
            meta_(const uint32_t &literal, const uint32_t &level)
                : lit(literal), lvl(level) {}
        } meta;
        uint64_t data;
        // genau eine der folgenden beiden Zeilen wieder einkommentieren:
        // Literal() { new (&meta) meta_(); }
        // Literal() : meta() {}
    };
    
    int main() {
        Literal l;
        std::cout << l.meta.lit << '\n';
    }
    


  • Vielen Dank wob



  • Funktioniert einwandfrei. Kannst dus mir erklären? oder ein Stichwort zum googeln geben. Struct, union versteh ich einigermaßen ind was ein Konstruktor ist weiß ich auch. Aber deine Codezeilen versteh ich leider nicht und warum sie notwendig sind.



  • In einer Union darfst du nur genau eine der dort deklarierten Variablen benutzen. Der Compiler weiß aber nicht, welche davon du nutzen willst.

    Solange du nur "einfache Datentypen" drin hast, ist das aber wumpe, weil die ja nicht initialisert werden. Daher geht es dann so.

    Wenn aber einer der Typen einen Konstruktor hat, der auch was tut (in deinem Fall meta_::meta_), kann der Compiler nicht wissen, ob du in der Union jetzt entweder data oder meta verwenden willst. Daher gibt es keinen Standardkonstruktor mehr für die Union (denn soll der data oder meta oder gar nix initialisieren?).

    Daher wirst du aufgefordert, selbst einen Konstuktor für die Union zu schreiben. Mit Literal() : meta() {} sagst du, dass der Konstruktor in der Union den meta-Konstruktor aufrufen soll. Ebenso wäre gegangen: Literal() : data(0) {} - dann wäre eben data statt meta initialisiert worden.

    Wenn du das aber noch nicht im vorhinein weißt und abhängig von irgendwas entweder den einen oder anderen Datentyp nutzen willst, kannst zu mit dem Placement New arbeiten: Literal() { if (bedingung) new (&meta) meta_(); else ...; }

    Am besten liest du das irgendwo nach, meine Erklärungen sind gerne etwas ungenau und ggf. nicht 100% korrekt.



  • Und vergiss nicht für Klassentypen den Destruktor manuell aufzurufen.


Anmelden zum Antworten