In-class und brace initialization



  • Hallo,

    sagt mal, warum ist dies?

    struct S
    {
    	bool b;
    	int i = 1;
    };
    
    int main()
    {
    	S s = {};
    
    	cout << s.b << "/" << s.i << endl; // Asugabe: 204/1
    }
    

    Sollte nicht alles auf Null sein?
    Und wenn ich "S s = {false};" schreiben will, bekomme ich:

    error C2440: 'initializing' : cannot convert from 'initializer-list' to 'S'

    Bitte um Erklärung.
    Danke.



  • Diese Art Structs zu Initialisieren ist noch aus C-Zeiten und funktioniert daher nur für POD (Plain Old Data) Typen. POD heißt keinen Konstruktor/Destruktor/private Membervariablen/kein virtuellen Funktionen und sicher noch ein paar Sachen die mir gerade nicht einfallen. Dadurch das du i einen Standardwert von 1 zuweist kriegst du implizit einen Konstruktor und die Initialisierung funktioniert nicht mehr. Entweder du nimmst den Standardwert raus oder erstellst einen eigenen Konstruktor der dann auch alles auf 0 setzt.



  • Okay danke.

    Aber ich dachte, das ist die tolle neue C++11 Syntax (diese Klammern) 😕



  • Genau das nennt sich Uniform Initialization. Darum compiliert dein Beispiel mit S s = {} überhaupt erst weil das den implizit generierten Konstruktor ohne Parameter aufruft. Du könntest dein Struct so definieren:

    struct S
    {
        bool b;
        int i;
    
        S(bool b = false, int i = 1)
          : b(b), i(i)
        {
        }
    };
    

    Dann funktioniert das alles:

    S s0 = {};        // b = false, i = 1
    S s1 = {true};    // b = true,  i = 1
    S s2 = {true, 0}; // b = true,  i = 0
    

  • Mod

    Edit: Nicht ganz akkurat.


  • Mod

    Ich habe die Wurzel der Verwirrung gefunden. Es handelt sich hierbei um einen Standard'defekt' der tatsächlich erst mit C++14 bereinigt wurde: NSDMIs (non-static data member initializers) waren in C++11 in Aggregaten nicht erlaubt. In C++14 ist S aber ein Aggregat, die Ausgabe ist garantiert 0/1 und {false} ist ein gültiger Initializer. VC++ hat diesen Teil wahrscheinlich nicht implementiert und verhält sich C++11-konform. Sorry für meine voreilige Vehemenz.

    sebi707 schrieb:

    Diese Art Structs zu Initialisieren ist noch aus C-Zeiten und funktioniert daher nur für POD (Plain Old Data) Typen.

    Nein. Aggregate. Die mit PODs im Übrigen nicht viel zu tun haben.

    POD heißt keinen Konstruktor/Destruktor/private Membervariablen/kein virtuellen Funktionen und sicher noch ein paar Sachen die mir gerade nicht einfallen.

    Ja, da gibt es eine lange Liste. Übrigens können POD-Klassen private Membervariablen haben. Kannst ja ein bisschen mit std::is_pod rumspielen um dich vertraut zu machen.

    Aggregate können außerdem auch Destruktoren haben. Und Konstruktoren können sie selbstverständlich auch haben, nur keine die user-provided sind.



  • Super, danke für die Infos.



  • Arcoth schrieb:

    Nein. Aggregate. Die mit PODs im Übrigen nicht viel zu tun haben.

    Naja, in C++03 war ein POD mindestens schonmal ein Aggregate. In C++11 wurde bei PODs dann viel geändert und die Unterschiede zwischen POD und Aggregate wurden größer. Immerhin hab ich mal wieder was neues gelernt.


  • Mod

    Weil mir grad langweilig war, hier ein mini-Artikel:

    POD-structs

    Standardlayout-structs1 sind (mittlerweile) folgendermaßen beschränkt:

    • Nur Standardlayout-Member oder -Basisklassen, wobei höchstens eine Basisklasse eines bestimmten Typs (letzteres eingeführt durch #1813).
    • Keine virtuellen Funktionen oder virtuelle Basisklassen
    • Alle Member haben dieselben access rights (i.e. alle entweder public , private oder protected ).
    • Member/Bitfields dürfen nicht verstreut werden.2

    Kleines Beispiel:

    struct A {private: int i;}; // SL
    struct B : A {};            // SL
    struct C : B {int j;};      // Kein SL; Verstreute Member
    struct D : B, A {};         // Kein SL: Zwei Basisklassen vom Typ A
    

    Demo.

    POD-structs haben Standardlayout, dürfen aber zudem nur trivialle spezielle Memberfunktionen haben (was von der Anforderung triviale Klasse hervorgeht. Siehe auch #1363). Und sie müssen einen Destruktor und (mindestens) einen Default-Konstruktor haben.

    struct A { A(char const*); };                // Kein POD
    struct B { B(char const*); B() = default; }; // POD
    struct C { C(char const*); C() = delete ; }; // POD
    

    Demo 2.

    Aggregate

    Die Anforderungen an Aggregate sind deutlich marginaler - und anders.

    §8.5.1/1 schrieb:

    An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

    Gemeinsamkeiten

    Die einzige Anforderung die beide stellen, ist, dass keine virtuellen Funktionen und keine virtuellen Basisklassen existieren dürfen.
    Daher auch mein voriges Kommentar.

    Unterschiede

    Eigenschaften die ein Aggregat, nicht aber ein POD-struct haben darf:

    • Nicht-triviale spezielle Memberfunktionen, e.g. durch einen NSDMI wie im OP gezeigt
    • Member die kein Standardlayout haben

    Eigenschaften die ein POD-struct, nicht aber ein Aggregat vorzeigen kann:

    • private / protected Member
    • Konstruktoren die keine Move-/Kopier- oder Default-Konstruktoren sind
    • Basisklassen.

    -------------------------------------------------------------------------------
    1 Schließt Unions aus. Standardlayout-Unions sind Unions mit Standardlayout, und Standardlayout-Klassen sind entweder Standardlayout-Structs oder -Unions.
    2 I.e. es darf nicht ein Member in einer Basisklasse vorhanden sein und ein zweiter in der Klasse selbst oder in einer anderen Basisklasse.



  • 👍 👍 👍


Anmelden zum Antworten