return (*this);
-
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
-
Klar, viele Wege führen nach Rom. Und wie du ein Problem löst, hängt auch von deiner verwendeten Klasse ab (die beiden vorgestellten Ansätze dürften nur die gängigsten Vorgehensweisen darstellen).
@otze: Das kommt ganz darauf an, wo in temp etwas schief geht - wenn "copydata()" (der die Daten aus dem übergebenen Objekt nach this übernehmen soll) etwas schief geht, hast du in jedem Fall ein Problem.
-
CS schrieb:
@otze: Das kommt ganz darauf an, wo in temp etwas schief geht - wenn "copydata()" (der die Daten aus dem übergebenen Objekt nach this übernehmen soll) etwas schief geht, hast du in jedem Fall ein Problem.
copydata darf keinen code enthalten, der schiefgehen kann. thats it. um dies zu erreichen, musst du nur konsequent das pimpl idiom durchziehen, dann swapt copydata nur 2 pointer.
-
otze schrieb:
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
pimpl ist doof.
die guten klassen brauchen keinen dtor und deswegen auch weder copy-ctor noch zuweisungsop noch exceptionfreies swap.
-
volkard schrieb:
die guten klassen brauchen keinen dtor und deswegen auch weder copy-ctor noch zuweisungsop noch exceptionfreies swap.
Solange du nur mit "flachen" Strukturen arbeitest, mag das ja klappen. Aber spätestens bei der Pointer-Verarbeitung benötigst du die "großen 3" zur Verwaltung (entweder beim Pointer-Besitzer oder einer dazwischengeschalteten Smart-Pointer-Klasse).
PS: und STL ist auch keine Universallösung
PPS: könnte bitte ein Mod den obigen Beitrag von mir eliminieren?