Referenz-Member und CArray (VS2005)



  • Hallo zusammen,
    ich versuch gerade, sowas ähnliches wie redundante Datenhaltung zu realisieren und hab mir da ne kleine Klasse geschrieben, die folgendermassen aussieht (ob das Sinn macht lassen wir mal dahingestellt 🙂 :

    Header:

    #ifndef REDUNDANTVALUE_H
    #define REDUNDANTVALUE_H
    
    class AFX_EXT_CLASS CRedundantValue
    {
    private:
    	double data;
    	double& redvalue;
    
    public:
    	CRedundantValue();
    	CRedundantValue(const double& val);
    	CRedundantValue(const CRedundantValue& copyValue);
    	~CRedundantValue();
    
    	CRedundantValue& operator = (const CRedundantValue& copyValue);
    
    };
    #endif
    

    Quelldatei:

    #include "stdafx.h"
    #include "RedundantValue.h"
    
    CRedundantValue::CRedundantValue() : redvalue(data)
    {
    }
    
    CRedundantValue::~CRedundantValue()
    {
    }
    
    CRedundantValue::CRedundantValue(const double& dval) : redvalue(data)
    {
    	data = dval;
    }
    
    CRedundantValue::CRedundantValue(const CRedundantValue &copyValue) : redvalue(data)
    {
    	data = copyValue.data;
    }
    
    CRedundantValue& CRedundantValue::operator = (const CRedundantValue& copyValue)
    {
        if (this != &copyValue)
        {
            data = copyValue.data;
        }
        return *this;
    }
    

    Das scheinte auch zu funktionieren, bis ich mal mehrere dieser Objekte in einen CArray stopfte:

    CRedundantValue val1(1.0);
    CRedundantValue val2(2.0);
    CRedundantValue val3(3.0);
    CRedundantValue val4(4.0);
    CArray<CRedundantValue,CRedundantValue> testArray3;
    testArray3.Add(val1);
    testArray3.Add(val2);
    testArray3.Add(val3);
    testArray3.Add(val4);
    

    Auf einmal geht die Referenz im ersten Element flöten, aber warum ?

    Gruss CatDog11



  • Nachdem ich beim Debuggen durch die afxtempl.h schon die Vermutung hatte, da da was beim Kopieren schief geht, hab ich nun bei Microsoft die Bestätigung gefunden (glaub ich zumindest)

    http://support.microsoft.com/kb/822369/en-us

    Gruss CatDog11


  • Mod

    Das hat gar nichts damit zu tun.

    Dein Code kann nicht funktionieren!

    CRedundantValue::CRedundantValue(const CRedundantValue &copyValue) : redvalue(data)
    {
    	data = copyValue.data;
    }
    

    Was ist, wenn ein temporäres Object erzeugt wird?
    Dann spoeicherst Du eine Referenz auf das data Objekt dieses temporären Objektes.
    Irgendwann geht dieses Objekt aus dem Scope. Deine Referenz wird ungültig.

    Wenn Du Referenzen benutzt musst Du garantieren, dass die Objekte auf die sie verweisen auch existieren, solange Du diese Referenz nutzen willst.

    Dein Code speichert jedoch Referenzen auf temporäre Objekte was schon falsch ist.



  • Versteh ich nicht ganz wie das passieren kann, könntest du mir bitte ein kleines Beispiel geben ?

    Gruss CatDog11


  • Mod

    CatDog11 schrieb:

    Versteh ich nicht ganz wie das passieren kann, könntest du mir bitte ein kleines Beispiel geben ?

    Dein Beispiel ist doch perfekt um den Fehler zu zeigen.

    Selber Effekt hier:

    const double &RefToDouble()
    {
        double x = 5;
        return cx;
    }
    
    void Foo()
    {
        const double &x = RefToDouble();
        // y verweist auf ein Objekt das nicht mehr existiert.
    ...
    }
    


  • Martin, kleiner Flüchtigkeitsfehler: Du definierst x, gibst aber cx zurück.

    Ansonsten gibt der Compiler in solchen Fällen auch eine Warnung, sofern Level 4 aktiviert ist:

    warning C4172: Adresse einer lokalen Variablen oder eines temporären Werts wird zurückgegeben
    


  • Irgendwie steh ich immer noch aufm Schlauch. Dein Beispiel ist mir klar. x verweist auf die Adresse der nicht mehr existierenden Variable aus RefToDouble.
    Wenn ich bei mir aber

    CRedundantValue test1(33.0);
    CRedundantValue test2(test1);
    

    genauer anschaue, haben test1 und test2 zwar dieselben Werte, aber völlig unterschiedliche Speicherbereiche. Wo genau liegt denn mein Denkfehler ?


  • Mod

    Bis dahin ist alles klar. Nur wenn Du nun Objekte in den Array packst werden temporäre Objekte evtl. angelegt, also es wird evtl. eines Deiner Objekte erst kopiert und dann eingetragen. Dann geht das temporäre Objekt aus dem Scope und Du hast den Schlamassel.

    Solche Art von Referenzen zu speichern ist einfach inkorrekt.


Anmelden zum Antworten