Verständnisfrage



  • Hallo, erst mal sorry für die Überschrift, aber mir ist tatsächlich kein besserer Titel zu dem Thema eingefallen. Ich demonstriere mein Problem mal eben anhand dieser Methoden :

    Array2D& assign(Array2D a)		
    	{
    		swap(a);
    		return *this;
    	}
    
    	void swap (Array2D& a) {
    		/*	
    		SO AKTZEPTIERT DER COMPILER ALLES
    		_________________________________
    		size_t temp = zeilen;
    		zeilen = a.zeilen;
    		a.zeilen = temp;
    		temp = spalten;
    		spalten = a.spalten;
    		a.spalten = temp;
    		T* tmp = ptr;
    		ptr = a.ptr;
    		a.ptr = tmp;
    		*/
    		// DAS WÄRE "meine Variante: "
    		zeilen = a.zeilen;
    		spalten = a.spalten;
    		T* tmp = ptr;
    		ptr = a.ptr;
    		a.ptr = tmp;
    	}
    	Array2D(const Array2D& a)
    		: zeilen(a.zeilen), spalten(a.spalten), ptr(new T[a.zeilen*a.spalten]) {
    			const int ANZ = zeilen* spalten;
    			for (size_t i=0; i<ANZ; ++i) {
    				ptr[i] = a.ptr[i];
    			}
    	}
    	~Array2D() { delete [ ] ptr; }
    

    Kann mir jemand erklären, wieso ich bei der Methode "swap" die Zeilen und die Spalten an das übergebene Objekt "a" zuweisen muss?
    Das a den Pointer von *this übergeben bekommen muss dient ja der "Zerstörung" des alten Speicherplatzes, aber wieso zur Hölle müssen die Zeilen und Spalten auch an "a" zugewiesen werden?
    Für den Destruktor ist das doch irrelevant, oder?!



  • "swap" bedeutet "tauschen".

    int a = 3;
    int b = 5;
    std::swap(a,b);
    
    // jetzt gilt: a == 5, b == 3)
    


  • Lass das swap so wie es war und füge Deinen code ins assign ein und lass dort den Aufruf von swap weg 😉 Beim ptr lässt Du die Tauscherei natürlich dann auch weg 😉

    swap = tauschen
    assign = zuweisen

    Array2D& assign(Array2D a)     
        {
            zeilen = a.zeilen;
            spalten = a.spalten;
            ptr = a.ptr;
            return *this;
        }
    
        void swap (Array2D& a) {
            size_t temp = zeilen;
            zeilen = a.zeilen;
            a.zeilen = temp;
            temp = spalten;
            spalten = a.spalten;
            a.spalten = temp;
            T* tmp = ptr;
            ptr = a.ptr;
            a.ptr = tmp;
        }
        Array2D(const Array2D& a)
            : zeilen(a.zeilen), spalten(a.spalten), ptr(new T[a.zeilen*a.spalten]) {
                const int ANZ = zeilen* spalten;
                for (size_t i=0; i<ANZ; ++i) {
                    ptr[i] = a.ptr[i];
                }
        }
        ~Array2D() { delete [ ] ptr; }
    


  • Bei swap möchtest du doch die beiden Objekte vertauschen! Bei deiner Variante würdest du nur ptr vertauschen und die Spalten und Zeilen nur kopieren.

    Kürzer (und damit besser lesbar) wäre also die Variante mittels std::swap (aus der Standard C++ Library):

    void swap (Array2D& a)
    {
      std::swap(zeilen, a.zeilen);
      std::swap(spalten, a.spalten);
      std::swap(ptr, a.ptr);
    }
    

    Edit: Der Trick beim assign besteht darin, daß dort ein lokales Objekt 'a' (anstatt einer Referenz) benutzt wird, so daß nach dem swap-Aufruf dieses Objekt (in dem nun die Daten des ursprünglichen Objekts stehen) dann zerstört wird (d.h. der Destruktor aufgerufen wird).

    PS. Dies nennt sich dann Copy and swap idiom



  • Danke erstmal für die Antworten!
    Ich möchte mich direkt auf ein Zitat lehnen, da ich meine Frage vermutlich undeutlich gestellt habe :

    Bei swap möchtest du doch die beiden Objekte vertauschen! Bei deiner Variante würdest du nur ptr vertauschen und die Spalten und Zeilen nur kopieren.

    Das Prinzip ist mir relativ klar, aber das Objekt "a" wird doch ohnehin nachdem "assign" ausgeführt wurde gelöscht. Von daher kann ich nachvollziehen, dass die Pointer vertauscht werden (alter Speicherplatz wird gelöscht ), aber wieso weise ich dem Objekt a noch die Zeilen und Spalten zu, wenn a ohnehin nach assign nicht mehr existiert? Zur Löschung benötige ich doch nur den Pointer (die alte "Startadresse" des Arrays"), oder inwiefern vertue ich mich ?



  • du verwechselst das schon wieder.

    "assign" = Zuweisung. Du holst die Werte aus einem anderen Objekt. Das andere Objekt wird anschließend weggeworfen, da copy per value.

    "swap" = tauschen. Du tauschst die Werte von zwei Objekten. Das andere Objekt wird daher per Referenz übergeben und existiert nach dem Aufruf weiter.



  • Cre schrieb:

    Das Prinzip ist mir relativ klar, aber das Objekt "a" wird doch ohnehin nachdem "assign" ausgeführt wurde gelöscht. Von daher kann ich nachvollziehen, dass die Pointer vertauscht werden (alter Speicherplatz wird gelöscht ), aber wieso weise ich dem Objekt a noch die Zeilen und Spalten zu, wenn a ohnehin nach assign nicht mehr existiert? Zur Löschung benötige ich doch nur den Pointer (die alte "Startadresse" des Arrays"), oder inwiefern vertue ich mich ?

    Dein Code, Deine Regeln.
    Aber selbst, wenn Du swap() nur in assign() aufrufst, finde ich die Benamsung irritierend - ein swap() , dass ein bisschen tauscht... 🙂
    Wenn Du Dein assign() mit swap() schreiben willst, dann mit std::swap nur auf den Speicher

    Array2D& assign(Array2D a)    
        {
            using std::swap;
            zeilen = a.zeilen;
            spalten = a.spalten;
            swap(ptr, a.ptr);
            return *this;
        }
    

    o.ä.
    Finde ich persönlich auch nicht sofort ersichtlich, wie und warum da was passiert, aber immerhin.
    Dein swap() sollte aber wirklich komplett tauschen - so dass überall die Invariable "ptr zeigt auf Speicher der Größe spalten*zeilen" gilt. Alles andere wird Dir auf die Füße fallen.

    MichelRT schrieb:

    Array2D& assign(Array2D a)     
        {
            zeilen = a.zeilen;
            spalten = a.spalten;
            ptr = a.ptr;
            return *this;
        }
    

    Da ist doch ein double delete vorprogrammiert.


Log in to reply