[solved] Initialisierungsreihenfolge in Initialisierungsliste von Konstruktor



  • Hallo,

    hab grad eben so just for fun mal versucht, Arrays in der Initialisierungsliste zu allozieren

    TimeoutHandler() : 
    		reactor( NULL ), 
    		isStarted( false ), 
    		cntr( 0 ), 
    		picWidth( 512 ), 
    		picHeight( 512 ),
    		bufferSize( picWidth * picHeight * 3 ),
    		rgbBuffer( new unsigned char[bufferSize] ),
    		jpegBuffer( new unsigned char[bufferSize] ),
    		compressor( new JPEGCompressor )
    		{};
    

    und wundere mich jetzt doch ein wenig, dass das nicht geht -- und zwar aus einem Grund, den ich nicht erwartet hätte: Zum Zeitpunkt des Aufrufs von operator new[] hat bufferSize irgendeinen abstrusen hohen Wert, also vermutlich Speichermüll, obwohl picWidth und picHeight beide korrekt auf 512 gesetzt sind. Aber die Reihenfolge der Initialisierung ist doch definiert, oder nicht? Ich sehe doch dauernd Initialisierungslisten, in denen die korrekte Initialisierung eines Werts vom vorhergehenden abhängt?

    <edit>
    achja, picWidth und picHeight sind vom Typ int, bufferSize ist ein size_t, also Überlauf kommt nicht in Frage.
    </edit>



  • Die Reihenfolge der Initialisierung der Variabeln gibt die Deklaration (Header) vor (nicht die Impl.).
    Die Objekterzeugung mit new würde ich in den Ctor Body verschieben.



  • Autsch. Hab scho sowas in der Art vermutet... Dann ist das ja total explosiv, sowas zu machen, warum tut das dann alle Welt? 0_0

    simon.gysi schrieb:

    Die Objekterzeugung mit new würde ich in den Ctor Body verschieben

    Stimmt, find ich auch -- war wie gesagt nur mal ein Versuch um zu sehen ob der Compiler das überhaupt frisst...

    Danke!



  • iko79 schrieb:

    Dann ist das ja total explosiv, sowas zu machen, warum tut das dann alle Welt? 0_0

    Warning Level hochdrehen, dann sollte ein vernünftiger Compiler Dir sagen, dass die Initialisierungsreihenfolge nicht stimmt.

    simon.gysi schrieb:

    Die Objekterzeugung mit new würde ich in den Ctor Body verschieben.

    Warum? Ist gerade im Hinblick auf Smartpointer nicht optimal (zuerst wird leer konstruiert, dann ersetzt, zudem ist ein Aufruf einer reset-Methode notwendig).



  • LordJaxom schrieb:

    Warum? Ist gerade im Hinblick auf Smartpointer nicht optimal (zuerst wird leer konstruiert, dann ersetzt, zudem ist ein Aufruf einer reset-Methode notwendig).

    Weiß nicht recht, wenn der Konstruktor unter Umständen Ausnahmen auslöst wirds dann kompliziert find ich (auch zu debuggen). In Bezug auf Smartpointer hast schon recht, aber bei nicht performance-kritischem Code (wie in diesem Fall) spar' ich mir die Stolpersteine dann. Ist halt auch Geschmackssache.

    LordJaxom schrieb:

    Warning Level hochdrehen, dann sollte ein vernünftiger Compiler Dir sagen, dass die Initialisierungsreihenfolge nicht stimmt.

    Cool, danke!



  • iko79 schrieb:

    Autsch. Hab scho sowas in der Art vermutet... Dann ist das ja total explosiv, sowas zu machen, warum tut das dann alle Welt? 0_0

    Die Initialisierungsliste sollte man immer in der Reihenfolge identisch wie im Header halten. Dann passiert dies auch nicht 😉
    Dafür die Initialisierungsliste zu verteufeln ist auch der falsche Weg - einiges geht schließlich nur und ausschließlich mit dieser. Und in irgendeiner definierten Reihenfolge muss die Initialisierung nunmal vonstatten gehen...

    Zu new bin ich auch LordJaxom Meinung. Ein new gehört in die Initialisierungsliste (Thema Smartpointer und Exceptionsicherheit...).

    cu André



  • iko79 schrieb:

    LordJaxom schrieb:

    Warum? Ist gerade im Hinblick auf Smartpointer nicht optimal (zuerst wird leer konstruiert, dann ersetzt, zudem ist ein Aufruf einer reset-Methode notwendig).

    Weiß nicht recht, wenn der Konstruktor unter Umständen Ausnahmen auslöst wirds dann kompliziert find ich (auch zu debuggen). In Bezug auf Smartpointer hast schon recht, aber bei nicht performance-kritischem Code (wie in diesem Fall) spar' ich mir die Stolpersteine dann. Ist halt auch Geschmackssache.

    Also ich empfinde es eher als Stolperstein es nicht zu tun...

    class B {}
    class A
    {
      private:
        boost::scoped_ptr<B> b1;
        boost::scoped_ptr<B> b2;
        boost::scoped_ptr<B> b3;
    
      public:
        A()
        : b1(new B),
          b2(new B),
          b3(new B)
        {
          // Hier ist keine Sonderbehandlung mehr nötig, da im Ausnahmefall die
          // Smartpointer hinter sich aufräumen. Nehmen wir an das b2 nicht
          // Konstruiert werden kann (new-exception) wird b1 wieder gelöscht.
        }
    };
    

    Und ob ich nun die Exceptionbehandlung im Konstruktor oder über die Smartpointer mache, nicht sich performancetechnisch nicht viel, da im Fehlerfall imho eh der Konstruktor per Exception beendet werden sollte...

    cu André



  • Wie gesagt, je nach Anwendungsfall: Unter der Verwendung von Smartpointern machts Sinn. Nachdem in meinem Fall keine verwendet werden würde b1 liegen bleiben wenn b2 nicht konstruiert werden kann.



  • @iko79: Auch wenn du das "new" in den ctor body verschiebst bringt dir das noch nix, da der dtor nicht aufgerufen wird wenn der ctor mit einer Exception verlassen wurde. Ergo müsstest du im ctor body ein try-catch reinbasteln, was zumindest ganz furchtbar hässlich ist, im schlimmsten fall noch andere seiteneffekte hat, oder einfach vergessen wird.

    Daher: Smart-Pointer oder eigene RAII Klassen verwenden.


Anmelden zum Antworten