Compilerfehler oder ungültiger Code? - Referenz mit ?: initialisieren



  • Hi,
    ich bin gestern über einen seltsamen Fehler gestolpert. Mein Compiler (MSC 😎 verhielt sich leider nicht so wie erwartet.
    Es geht im Grunde darum, eine Referenz zur Laufzeit mit Hilfe des ?: Operators zu initialisieren. Da das Programm relativ komplex ist, hab ich mal ein vereinfachtes Testprogramm gemacht, das den Fehler reproduziert.

    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    
    class A
    {
    public:
    	A& operator =(const A&)
    	{
    		cout << "copy op: A" << endl;
    		return *this;
    	}
    	A()
    	{
    		cout << "default ctor: A" << endl;
    	}
    	A(const A&)
    	{
    		cout << "copy ctor: A" << endl;
    	}
    	virtual ~A()
    	{
    		cout << "dtor: A" << endl;
    	}
    };
    
    class B
    	: public A
    {
    public:
    	B& operator =(const B&)
    	{
    		cout << "copy op: B" << endl;
    		return *this;
    	}
    	B()
    	{
    		cout << "default ctor: B" << endl;
    	}
    	B(const B&)
    	{
    		cout << "copy ctor: B" << endl;
    	}
    	~B()
    	{
    		cout << "dtor: B" << endl;
    	}
    };
    
    void test(bool x)
    {
    	A a;
    	B b;
    	cout << "?: begin" << endl;
    	A& c = x ? a : b; // (1)
    //	A& c = x ? a : static_cast<A&>(b); // (2)
    	cout << "?: end" << endl;
    	cout << "&a = " << static_cast<void*>(&a) << endl;
    	cout << "&b = " << static_cast<void*>(&b) << endl;
    	cout << "&c = " << static_cast<void*>(&c) << endl;
    }
    
    int main()
    {
    	cout << "x = ";
    	int x;
    	cin >> x;
    	test(x != 0);
    	return 0;
    }
    

    Wie man sieht, gibt es eine Basisklasse (A) und eine davon abgeleitete Klasse (B). In der Funktion test wird nun von jeder Klasse jeweils eine Instanz (a, b) erstellt. Anschliessend wird eine Referenz (c) auf die Basisklasse erzeugt, welche, dem boolschen Parameter entsprechend, entweder mit der einen oder der anderen Instanz initialisiert wird. Und genau hier tritt das Problem auf. Als Ausgabe erhalte ich folgendes:

    MSC - test(false)

    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    copy ctor: A
    copy ctor: A
    dtor: A
    ?: end
    &a = 0012FF54
    &b = 0012FF4C
    &c = 0012FF50
    dtor: A
    dtor: B
    dtor: A
    dtor: A
    

    MSC - test(true)

    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    copy ctor: A
    ?: end
    &a = 0012FF54
    &b = 0012FF4C
    &c = 0012FF50
    dtor: A
    dtor: B
    dtor: A
    dtor: A
    

    Wie man sieht, sorgt operator ?: dafür, dass ein bzw mehrere temporäre Objekte erstellt werden. Das ansich ist ja schon unverständlich (da vollkommen unnütz), wäre aber noch keine Tragödie. Diese entsteht erst dadurch, dass die Referenz (c) weder auf die eine noch die andere Instanz verweist. Was man an den Adressen gut sehen kann.
    Hat also der MSC hier Probleme, wenn die beiden Assignment Ausdrücke beim ?: Operator nicht vom gleichen Typ sind? Probiert man es statt Zeile (1) mit Zeile (2), funktioniert alles problemlos.
    Was mich weiter bestärkt, dass es sich um einen Compiler Fehler handelt, ist, dass mit GCC alles einwandfrei funktioniert.

    GCC - test(false)

    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    ?: end
    &a = 0x22ff10
    &b = 0x22ff00
    &c = 0x22ff00
    dtor: B
    dtor: A
    dtor: A
    

    GCC - test(true)

    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    ?: end
    &a = 0x22ff10
    &b = 0x22ff00
    &c = 0x22ff10
    dtor: B
    dtor: A
    dtor: A
    

    Was sagt ihr dazu? Ist das ein Compiler Fehler? Oder doch nur ungültiger Code?
    Würde mich freuen, wenn ihr ausserdem das Testprogramm mit eurem Compiler mal ausprobiert und die Ergebnisse hier postet.

    btw:
    Mit dem BCC 5.5 ergeben sich ähnliche Probleme wie mit dem MSC.



  • Ob es gültig ist oder nicht - ich weiß es nicht. Ich würde solchen Code aber vermeiden.

    Hier mal die Ergebnisse mit dem KAI-Compiler.

    x = 0
    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    ?: end
    &a = 11fffbd08
    &b = 11fffbd00
    &c = 11fffbd00
    dtor: B
    dtor: A
    dtor: A
    
    x = 1
    default ctor: A
    default ctor: A
    default ctor: B
    ?: begin
    ?: end
    &a = 11fffbd08
    &b = 11fffbd00
    &c = 11fffbd08
    dtor: B
    dtor: A
    dtor: A
    


  • Hallo,
    laut 5.16/3 ist der Code ok. Eine Kopie darf dabei nicht erzeugt werden. Das Verhalten des gccs ist also korrekt.



  • 7H3 N4C3R schrieb:

    Ob es gültig ist oder nicht - ich weiß es nicht. Ich würde solchen Code aber vermeiden.

    Bin für alle Vorschläge offen. Offenbar kennst du 'ne bessere Möglichkeit, eine Referenz laufzeitabhängig zu initialisieren.



  • groovemaster schrieb:

    7H3 N4C3R schrieb:

    Ob es gültig ist oder nicht - ich weiß es nicht. Ich würde solchen Code aber vermeiden.

    Bin für alle Vorschläge offen. Offenbar kennst du 'ne bessere Möglichkeit, eine Referenz laufzeitabhängig zu initialisieren.

    willste ihn nur hierzu zwingen?

    A& c = *(x ? &a : &b);
    

    ob vielleicht schon

    A& c = x ? &a : (A&)b;
    

    ausreicht?



  • volkard schrieb:

    A& c = x ? &a : (A&)b;
    

    Ich bin etwas enttäuscht. Volkard benutzt C-Casts in C++? Mein Weltbild es zutiefst erschüttert. 🙂
    Aber mal ernsthaft, mit beiden Varianten lässt sich der Fehler leicht umgehen. Das ansich ist ja auch nicht das Problem. Es ist nur seltsam, dass die einfachste Variante (schreibtechnisch gesehen) nicht funktioniert.



  • groovemaster schrieb:

    Es ist nur seltsam, dass die einfachste Variante (schreibtechnisch gesehen) nicht funktioniert.

    ein c++ compiler ist 'ne ziemlich komplexe sache. da hat das mickrigweich-produkt wohl 'nen bug. schreib denen 'ne mail damit sie's fixen


Anmelden zum Antworten