Fordert Copy-Initialization auch Copy-Construction?



  • Ich habe zur Zeit einen Disput mit einem Kollegen meinerseits. Es geht darum, ob eine Copy-Initialization aus einem temporären Objekt einen Copy-Constructor erfordert, auch wenn dieser wegoptimiert wird. Ich meine ja, er meint nein. Interessanterweise sehen auch unsere Compiler das unterschiedlich. Wenn der Copy-Constructor direkt unbenutzbar gemacht wird, werfen beide einen Fehler (was meine Meinung bestätigt), über Vererbung jedoch sehen sie es etwas anders.

    Folgendes Beispiel compiliert keiner von beiden:

    struct X
    {
        X() {}
    private:
        X( X const& );
        X& operator=( X const& );
    };
    
    int main()
    {
        X x = X();
    }
    

    Folgendes Beispiel wird jedoch vom MSVC++ 8.0 übersetzt, vom G++ 3.3.5 und G++ 4.1 jedoch nicht:

    #include <boost/noncopyable.hpp>
    
    struct X: boost::noncopyable
    {
        X() {}
    };
    
    int main()
    {
        X x = X();
    }
    

    Wer hat Recht und warum?



  • Das im Ausgangsposting beschriebene Problem wird noch schlimmer, wenn man ein template

    template <typname T> class C
    {
       void f()
       {
          T t = T();
       }
    };
    

    verwenden will. Instanziert mit int geht es gut, mit von boost::noncopyable abgeleiteter Klasse aber nicht.

    Die alternative für f()

    void f()
       {
          T t;
       }
    

    hinterlässt bei int die lokale Variable t uninitialsiert und T t(); schreiben geht nicht bei Klassen mit default Konstruktoren.

    Grüße
    Dieter



  • du hast recht und es steht in 12.2/1: "Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created.", und laut 8.5/14/4/3 wird hier ein temporäres objekt erzeugt, dass dann für die direct-initialization verwendet wird. bei X x = X() wird zwar kein temporäres objekt erzeugt (8.5/14/4/2), aber wenn der es keinen passenden ctor gibt, dann funktioniert es auch nicht.

    /edit:
    msvc hat einen bug, weil sie 8.5/14/4/2 falsch interpretieren. siehe http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101735
    vielleicht hat sie auch nur 12.3.1/2 verwirrt 😃


  • Mod

    LordJaxom schrieb:

    Ich habe zur Zeit einen Disput mit einem Kollegen meinerseits. Es geht darum, ob eine Copy-Initialization aus einem temporären Objekt einen Copy-Constructor erfordert, auch wenn dieser wegoptimiert wird. Ich meine ja, er meint nein.

    Du hast recht, wie auch schon erklärt wurde.

    Interessanterweise sehen auch unsere Compiler das unterschiedlich. Wenn der Copy-Constructor direkt unbenutzbar gemacht wird, werfen beide einen Fehler (was meine Meinung bestätigt), über Vererbung jedoch sehen sie es etwas anders.

    Folgendes Beispiel compiliert keiner von beiden:

    Folgendes Beispiel wird jedoch vom MSVC++ 8.0 übersetzt, vom G++ 3.3.5 und G++ 4.1 jedoch nicht:

    #include <boost/noncopyable.hpp>
    
    struct X: boost::noncopyable
    {
        X() {}
    };
    
    int main()
    {
        X x = X();
    }
    

    Wer hat Recht und warum?

    Ein Fehler des MSVC, allerdings kein Problem von 8.5
    In diesem Falle hat X ja einen geeigneten Copy-Konstruktor, der auch public ist (da implizit deklariert) - nur kann dieser nicht definiert werden. Die Bemerkung in 12.8/7

    [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2). ]

    ist da sehr eindeutig. Dass der Compiler durchaus nach einem passenden Copy-Konstruktor sucht erkennt man leicht, wenn man eine eigene Basisklasse geeignet schreibt:

    class A
    {
        A(A&);
        void operator=(A&);
    };
    struct X : A
    {
        X() {}
    };
    
    int main()
    {
        X x = X();
    }
    

    Hier verweigert auch msvc die Zusammenarbeit.

    Edit: Ganz zum Schluss wird das auch hinter obigem Link erklärt, ich hatte auf die zitierten Stellen des Standards geschaut.


Anmelden zum Antworten