return (*this);
-
Danke,
ich habe jetzt irgedwie das komische Gefühl das ich das schonmal gefragt habe
-
yuhuuu, danke euch allen! hab's verstanden
-
MyClass& operator=(const MyClass& ob) { if(this != &ob) // nichts tun beim gleichen Objekt <--- wichtig! { } return *this; }
selbstzuweisung kann man auch anders abfangen, weiss grad nicht wie!!???
cu
-
operator= schreiben profis wie folgt:
// Now writing the assignment operator is super easy Shape& Shape::operator=(const Shape& rhs) { Shape temp(rhs); temp.Swap(*this); return *this; }
-
............. schrieb:
operator= schreiben profis wie folgt:
// Now writing the assignment operator is super easy Shape& Shape::operator=(const Shape& rhs) { Shape temp(rhs); temp.Swap(*this); return *this; }
oder machmal
// Now writing the assignment operator is super easy Shape& Shape::operator=(Shape const& rhs) { Shape tmp(rhs); Swap(tmp); return *this; }
-
tokio schrieb:
if(this != &ob) // nichts tun beim gleichen Objekt <--- wichtig!
Das ist aber nicht der Normalfall. Selbstzuweisung abzufangen ist nur in sehr wenigen Fällen erforderlich. Korrekt aufgebaute Klassen können op= auch so problemlos handeln. Und dazu muss man nichtmal auf den swap Trick zurückgreifen.
-
wo liegt hier der unterschied?
Shape tmp(rhs); <-- locales objekt erstellen, copy constr. wird aufgerufen... 1.) temp.Swap(*this); <-- versteh ich nicht, swap tauscht ja, wie verhindert es selbstzuweisung? 2.) Swap(tmp); <-- unterschied zum obrigen swap? return *this;
-
Hallo,
1.) temp.Swap(*this); <-- versteh ich nicht, swap tauscht ja, wie verhindert es selbstzuweisung?
gar nicht. Eine Selbstzuweisung erzeugt hier aber auch keinen Fehler.
2.) Swap(tmp); <-- unterschied zum obrigen swap?
Weniger Schreibarbeit. Eine Dereferenzierung weniger.
-
Problem bei Selbstzuweisung ist, daß du unter Umständen die Daten löschen würdest, die du gerade kopieren wolltest:
class test { int* val; test& operator=(const test& other) { delete[] val; //Aufräumen val=other.val;//hier crasht es bei selbstzuweisung (weil ich gerade other.val gelöscht habe) return *this; } }
Mittels swap (es gibt übrigens noch die dritte Variante "swap(*this,other)", die aber idR langsamer ist) wird das Problem umgangen.
-
CS schrieb:
Mittels swap (es gibt übrigens noch die dritte Variante "swap(*this,other)", die aber idR langsamer ist) wird das Problem umgangen.
warum langsamer?
sehe keinen grund. sehe nur, daß selbstzuweisungen so extrem selten sind, daß es schneller wäre, code zu bauen, der den test nicht braucht und im falle iener selbstzuweisung durchaus lahm sein darf.
-
CS schrieb:
Problem bei Selbstzuweisung ist, daß du unter Umständen die Daten löschen würdest, die du gerade kopieren wolltest:
class test { int* val; test& operator=(const test& other) { delete[] val; //Aufräumen val=other.val;//hier crasht es bei selbstzuweisung (weil ich gerade other.val gelöscht habe) return *this; } }
ROFL. Sehr schön. Darf ich mal fragen, warum ich da nur ein delete sehe, aber kein new? Achso, sollte nur ein Beispiel sein, um den Bedarf von Selbstzuweisungstests zu zeigen. Nunja, netter Versuch, aber wirkungslos. Die generelle Vorgehensweise ohne swap ist: neuen Speicher anfordern - kopieren - alten Speicher freigeben. Keine Lecks, kein Leichengestochere. Punkt.
Auf Selbstzuweisung zu testen macht idR keinen Sinn. Das ist ein Ausnahmefall, der nur sehr selten eintritt. Man sollte nicht die restlichen Fälle dafür bestrafen. Und wie Volkard schon andeutete, ein langsamerer Durchlauf mit Selbstzuweisung tut weniger weh, als viele langsamerere Durchläufe ohne Selbstzuweisung. Zudem ist das Laufzeitverhalten konstanter.
-
volkard schrieb:
CS schrieb:
Mittels swap (es gibt übrigens noch die dritte Variante "swap(*this,other)", die aber idR langsamer ist) wird das Problem umgangen.
warum langsamer?.
er meinte statt langsamer endlos rekursiv
template<class T> void swap(T o1,T o2){ T temp=o1; o1=o2; o2=temp; }
und wenn der op= selber swap aufruft wirds lustig...
-
volkard schrieb:
CS schrieb:
Mittels swap (es gibt übrigens noch die dritte Variante "swap(*this,other)", die aber idR langsamer ist) wird das Problem umgangen.
warum langsamer?
Langsamer im Vergleich zu der Member-Implementation (ein globales swap würde dreimal den Kopier-Konstruktor bzw. Zuweisungsoperator aufrufen - ein swap als Methode *kann* nur die internen Daten austauschen).
groovemaster schrieb:
Sehr schön. Darf ich mal fragen, warum ich da nur ein delete sehe, aber kein new?
Weil ich da etwas schnell gearbeitet habe
Stimmt, eigentlich müßte anstelle des "val=other.val" noch ein new und memcopy kommen.
Und wie Volkard schon andeutete, ein langsamerer Durchlauf mit Selbstzuweisung tut weniger weh, als viele langsamerere Durchläufe ohne Selbstzuweisung. Zudem ist das Laufzeitverhalten konstanter.
Der Punkt dabei ist, daß die Implementierung mit swap() doppelt so viele Zuweisungen und entsprechend viel Hilfsspeicher benötigen würde als die Sicherheitsabfrage:
ob& ob::operator=(const ob& other) { if(this!=&other) { copydata(other); } return *this; } // ein Pointer-Vergleich, eine Kopieroperation ob& ob::operator=(const ob& other) { ob tmp=other; copydata(tmp); return *this; } // zwei Kopieroperationen
Nun entscheide selbst, was besser ist
-
Die Sicherheizabfrage kann man aber mit nem überladenen Operator auch für dumm verkaufen.
-
7H3 N4C3R schrieb:
Die Sicherheizabfrage kann man aber mit nem überladenen Operator auch für dumm verkaufen.
Klar kannst du das, wenn du dir wirklich Mühe geben willst, deine Klassen zu schrotten
-
CS schrieb:
ob& ob::operator=(const ob& other) { ob tmp=other; copydata(tmp); return *this; }
Nun entscheide selbst, was besser ist
das da ist besser. Es ist exception sicher! wenn in tmp was schiefgeht, ist *this unverändert und damit definiert!
-
CS schrieb:
7H3 N4C3R schrieb:
Die Sicherheizabfrage kann man aber mit nem überladenen Operator auch für dumm verkaufen.
Klar kannst du das, wenn du dir wirklich Mühe geben willst, deine Klassen zu schrotten
Sagt ja niemand, dass man das mit direkter Absicht macht. Vielmehr als implizite Folge von irgendeinem anderen Effekt, den man gerne haben möchte.
-
gehen wir erstemal davon aus, daß jeder typ, bei dem man einen copy&swap-trick verwenden will, daß man dem auch ein schnelles und exceptionfreies swap verpaßt.
-
CS schrieb:
Und wie Volkard schon andeutete, ein langsamerer Durchlauf mit Selbstzuweisung tut weniger weh, als viele langsamerere Durchläufe ohne Selbstzuweisung. Zudem ist das Laufzeitverhalten konstanter.
Der Punkt dabei ist, daß die Implementierung mit swap() doppelt so viele Zuweisungen und entsprechend viel Hilfsspeicher benötigen würde als die Sicherheitsabfrage:
Ich hab ja auch nirgendwo geschrieben, dass du swap verwenden musst. Du kannst selbstverständlich auch einen sicheren, swap-freien op= ohne Abfrage auf Selbstzuweisung implementieren.
-
volkard schrieb:
gehen wir erstemal davon aus, daß jeder typ, bei dem man einen copy&swap-trick verwenden will, daß man dem auch ein schnelles und exceptionfreies swap verpaßt.
um dies zu erreichen, müsste man nur das pimpl-idiom konsequent durchziehen. Denn wenn pointer geswapt werden, kann nix schiefgehen