Copy-Constructor bei Array-Initialisierung - warum benötigt?



  • Hallo zusammen,

    im folgenden Code wird eine umständliche (jedoch gültige) Form der Array-Initialisierung verwendet. Zudem ist ein Copy-Constructor explizit vorhanden.

    class Element
    {
    public:
        Element() : value(1) {}
    
    private:
        // Copy ctor
        Element(const Element & object) : value(42) {}
    
    public:
        int value;
    };
    
    // Initialisierung
    static Element myArray[2] = { Element(), Element() };
    
    int main( int argc, char** argv, char** env )
    {
        cout << "Val 0: " << myArray[0].value << endl;
        cout << "Val 1: " << myArray[1].value << endl;
    }
    

    Das Interessante nun:
    Wenn man den Copy-ctor private macht (wie im Code-Beispiel), meckert der Compiler (gcc). Mach man ihn public, ist gcc zufrieden, jedoch wird der Copy-Constructor bei Ausführung nie aufgerufen (-O0). Die Ausgabe ist:
    `Val 0: 1

    Val 1: 1`

    Kann das jemand erklären? Warum wird der Copy-Ctor dann überhaupt verlangt?

    Wenn man die Initialisierungsliste weg lässt, da man sie sowieso nicht braucht, ist der Copy-ctor irrelevant und kann auch private sein:

    static Element myArray[2];
    

    Hinweis: bitte keine Ratschläge bezüglich Verwendung von std::vector oder anderer Array-Klassen! Es geht mir nur um den Copy-Ctor bei dieser Anordnung.
    ~Edit: ohne Container-Klasse, d.h. myArray direkt als static var~



  • Interessant.

    Element Container::myArray[Container::arraySize] = { {}, {} };
    

    kompiliert ebenfalls.
    Keine Ahnung.



  • Ich hab das Beispiel noch etwas eingedampft.

    Jockelx schrieb:

    Element Container::myArray[Container::arraySize] = { {}, {} };
    

    kompiliert ebenfalls.

    Ach ja: war C++03. 😉


  • Mod

    Copy-Elision ist schon eine lustige Sache. Es ist geregelt, dass dafür der Copy-Constructor verfügbar sein muss, aber es geht gerade darum, dass man ihn dann doch nicht aufruft.

    Ansonsten ist der Grund, warum du überhaupt einen Copy-Construcotr brauchst, dass gerade festgelegt ist, dass Arrays mit Kopien initialisiert werden.



  • Es ist gut möglich, dass GCC trotz -O0 eine explizit vom Standard erlaubte Copy Elision macht, die Elemente also direkt im Array konstruiert,
    und den Kopierkonstruktor nicht aufruft, obwohl - so meine Vermutung - der Standard vorschreibt, dass Element hier einen erreichbaren (nicht privaten)
    Kopierkonstruktor haben muss, der ja für den Fall dass keine Copy Elision stattfindet, auch wirklich benötigt wird.

    Für GCC könntest du es mal hiermit versuchen:

    -fno-elide-constructors
    The C++ standard allows an implementation to omit creating a temporary that is only used to initialize another object of the same type. Specifying this option disables that optimization, and forces G++ to call the copy constructor in all cases.

    Übrigens ist die Copy Elision direkt vom Standard erlaubt, und daher keine klassische "as-if"-Optimierung.
    Daher darf sich das Programm wie bei dir auch beobachtbar anders verhalten als es das ohne Optimierung täte.



  • Ah, wow!

    "Copy elision" also heißt das Zauberwort! 💡 😃

    Scheint ja so was Ähnliches (oder das Gleiche?) zu sein wie Return Value Optimization.

    Vielen Dank für die Erklärungen! Hilft weiter im Verständnis! 👍


  • Mod

    minastaros schrieb:

    Scheint ja so was Ähnliches (oder das Gleiche?) zu sein wie Return Value Optimization.

    RVO ist ein Einsatz von Copy Elision. Hier liegt aber ein anderer Art von Einsatz vor. Der Effekt ist natürlich ein ganz ähnlicher.


Log in to reply