[Gelöst] Empty Base Class Optimisation



  • Undefiniertes Verhalten, da es nicht festgelegt ist, dass alle Member von class in einer Reihe im Speicher liegen. Dein Compiler kann Padding adden, wenn er es als nötig erachtet.



  • Janjan schrieb:

    Undefiniertes Verhalten, da es nicht festgelegt ist, dass alle Member von class in einer Reihe im Speicher liegen. Dein Compiler kann Padding adden, wenn er es als nötig erachtet.

    zwischen ints? extrem unrealistisch. das scheint mir jetzt paragraphenreiterei zu sein.



  • volkard schrieb:

    Janjan schrieb:

    Undefiniertes Verhalten, da es nicht festgelegt ist, dass alle Member von class in einer Reihe im Speicher liegen. Dein Compiler kann Padding adden, wenn er es als nötig erachtet.

    zwischen ints? extrem unrealistisch. das scheint mir jetzt paragraphenreiterei zu sein.

    Es ist unwahrscheinlich, das stimmt. Aber so ist es. 😉 Wenn er ne komplexere Klasse hat (was höchstwahrscheinlich der Fall ist), dann trifft es zu.

    Aber in seinem Beispiel wäre es festgelegt, dass X und int an der selben Stelle liegen. Wie die interne Struktur von X ist, ist ja eine vollkommene andere Sache.



  • Janjan schrieb:

    volkard schrieb:

    Janjan schrieb:

    Undefiniertes Verhalten, da es nicht festgelegt ist, dass alle Member von class in einer Reihe im Speicher liegen. Dein Compiler kann Padding adden, wenn er es als nötig erachtet.

    zwischen ints? extrem unrealistisch. das scheint mir jetzt paragraphenreiterei zu sein.

    Es ist unwahrscheinlich, das stimmt. Aber so ist es. 😉 Wenn er ne komplexere Klasse hat (was höchstwahrscheinlich der Fall ist), dann trifft es zu.

    Aber in seinem Beispiel wäre es festgelegt, dass X und int an der selben Stelle liegen. Wie die interne Struktur von X ist, ist ja eine vollkommene andere Sache.

    Es ist festgelegt wann sich wo die Member einer klasse, sich im Speicher befinden.
    Und genau dass nutzt man aus, und um undefiniertes verhalten auszuschließen dürfen auch nur PODs verwendet werden. Virtuell , Zeiger etc sind in Unions verboten.

    Aber, Ich Zitiere :

    volkard schrieb:

    Warum steht da einmal 40, wo man doch 36 erwarten würde?



  • Bist du dir sicher? Gerade wegen Paddingsachen.

    struct Fubar
    {
      char a;
      int  b;
      char c;
    };
    

    Die größe dieser Struktur ist in der Regel 12 bytes, denn es wird zu folgendem:

    struct Fubar
    {
      char a;
      char p1[3];
      int  b;
      char c;
      char p2[3];
    };
    

    Man beachte _wo_ die Paddings sich befinden.



  • Speed schrieb:

    Es ist festgelegt wann sich wo die Member einer klasse, sich im Speicher befinden.

    Falsch.

    C++-Standard 9.2/12 schrieb:

    Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

    Speed schrieb:

    Und genau dass nutzt man aus

    Ja, und genau hier liegt auch das Problem. Gerade wenn man sich auf so tiefer Abstraktionsebene bewegt, schadet es nicht, mit den Garantien des Standards und den Compilereigenheiten etwas vertraut zu sein.

    Für deinen Fall kannst du versuchen, compilerabhängige Flags betreffend Padding zu setzen. Ich kenne mich mit g++ leider nicht so gut aus. Vielleicht ist der Compiler unter gewissen Umständen jedoch tatsächlich nicht in der Lage, die EBO (Empty Base Optimization) durchzuführen, sodass eine abgeleitete Klasse schlussendlich mehr Speicher als eigentlich erforderlich benötigt.



  • Janjan schrieb:

    Bist du dir sicher? Gerade wegen Paddingsachen.

    struct Fubar
    {
      char a;
      int  b;
      char c;
    };
    

    Die größe dieser Struktur ist in der Regel 12 bytes, denn es wird zu folgendem:

    struct Fubar
    {
      char a;
      char p1[3];
      int  b;
      char c;
      char p2[3];
    };
    

    Man beachte _wo_ die Paddings sich befinden.

    Paddings, hab ich beim Argumentieren vergessen...
    Aber ist mein Problem wirklich dadurch erklärbar, wenn man beachtet das es sich um ints(die stehts einen Speicherblock ausfüllen) handelt?
    In meinem Fall, besteht eine Klasse stehts aus einem Member der einen Speicherblock komplett ausfüllt(ints sind stehts plattform abhängig, char ist immer ein byte) und hat keine virtuellen vorfahren und funktionen die gemenaged werden müssen.

    Sei es doch der Fall, dann wär es mir umso wichtiger, wieso der effect nicht bei B1 und B2,auftritt, zu wissen.Auch interessant ist es zu erfahren ob es auch bei, anderen Compilern auftritt.

    Edit:

    union X 
    {
    char a[sizeof(int)];
    int b;
    };
    


  • Ich zitiere mal Nathan Myers:

    Nathan Myers schrieb:

    Update again: A whole family of related "empty subobject" optimizations are possible, subject to the ABI specifications a compiler must observe. (Jason Merrill pointed some of these out to me, years back.) For example, consider three struct members of (empty) types A, B, and C, and a fourth non-empty. They may, conformingly, all occupy the same address, as long as they don't have any bases in common with one another or with the containing class. A common gotcha in practice is to have the first (or only) member of a class derived from the same empty base as the class. The compiler has to insert padding so that they two subobjects have different addresses. This actually occurs in iterator adapters that have an interator member, both derived from std::iterator. An incautiously-implemented standard std::reverse_iterator might exhibit this problem.

    Vor allem er kursive Teil dürfte interessant für Dich sein.
    Den ganzen Text findest Du hier.



  • Tachyon schrieb:

    Ich zitiere mal Nathan Myers:

    Nathan Myers schrieb:

    Update again: A whole family of related "empty subobject" optimizations are possible, subject to the ABI specifications a compiler must observe. (Jason Merrill pointed some of these out to me, years back.) For example, consider three struct members of (empty) types A, B, and C, and a fourth non-empty. They may, conformingly, all occupy the same address, as long as they don't have any bases in common with one another or with the containing class. A common gotcha in practice is to have the first (or only) member of a class derived from the same empty base as the class. The compiler has to insert padding so that they two subobjects have different addresses. This actually occurs in iterator adapters that have an interator member, both derived from std::iterator. An incautiously-implemented standard std::reverse_iterator might exhibit this problem.

    Vor allem er kursive Teil dürfte interessant für Dich sein.
    Den ganzen Text findest Du hier.

    Vielen Dank, hat mir weitergeholfen!

    MFG Speed



  • BTW: VC liefert hier dreimal 36...



  • Hab ein bisschen rumprobiert und wiedermal hat mich g++ überrascht.
    Wie wir festgestellt haben, werden 4Byte extra verbraucht, wenn beide Klassen vorfahren haben, richtig?
    Der Nachfolgende Code beweist das es außerdem notwendig ist, dass es die selbe Klasse sein muss.
    Wiso macht es einen unterschied, ob es die selbe Klasse ist?

    #include <iostream>
    
    class A1{};
    class A2{};
    
    class B3:A1{ int A[3]; };
    class C3:A1{ B3 A[3];};
    class C4:A2{ B3 A[3];};
    
    int main()
    {
        std::cout<<"             "<<sizeof(C3) <<"  "<<sizeof(C4);
    //output[g++4.4.3]:                 40                36
    }
    

    //Edit urghh steht ja bereits im Zitiertem Text ;P



  • Eine kleine Frage, was erhoffst du von deinen Versuchen? :o



  • Speed schrieb:

    Der Nachfolgende Code beweist das es außerdem notwendig ist, dass es die selbe Klasse sein muss.
    Wiso macht es einen unterschied, ob es die selbe Klasse ist?

    Stand ja eigentlich in dem zitierte Text drin. Ich geb dir aber mal Code:

    C3 c;//stellen wir uns vor, dass wäre ohne Padding
    C3* p=&c;//okay, wirholen einfach die Addresse.
    A1* p2=static_cast<A1*>(p);//BÄM! Interpretiert der Compiler das Ding nun als Basisklassenzeiger der Klasse C3 oder von B3? bedenke: A[0] hat die selbe Addresse ohne Padding!
    


  • otze schrieb:

    C3 c;//stellen wir uns vor, dass wäre ohne Padding
    C3* p=&c;//okay, wirholen einfach die Addresse.
    A1* p2=static_cast<A1*>(p);//BÄM! Interpretiert der Compiler das Ding nun als Basisklassenzeiger der Klasse C3 oder von B3? bedenke: A[0] hat die selbe Addresse ohne Padding!
    

    [quote=G++]
    warning: ‘C3::A1’ contains empty classes which may cause base classes to be placed at different locations in a future version of GCC!
    [/quote]

    Muss ich mir darüber sorgen machen?
    ist das verhalten nicht g++ konform mit dem Standard?

    MFG Speed


Anmelden zum Antworten