Sutters operator=
-
Hallo,
ich hab gerade mal wieder meine Nase in Sutters Exceptional C++ gesteckt. Er macht dort seinen operator= unter Verwendung des ctor mit einem Swap, was einen no-throw garantiert. Ich hab es bisher immer anders herum gemacht: mein ctor benutzt den operator= um die Kopie anzulegen.
Wenn ich ein Swap mache, bei dem ich garantiere, das er keine exception wirft, dann kann ich doch lieber gleich garantieren, das mein opeartor= nix wirft und spare mir die temporäre Copy-Instanz.Volkard meinte in diesem alten Artikel:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-36357-and-highlight-is-sutter.html
,das ein Swap prinzipiell immer schick wäre. Ich verstehe nur nicht ganz, warum.
-
mein ctor benutzt den operator= um die Kopie anzulegen.
Generell ist es richtig Copy-Ctor und Op= abhängig voneinander zu implementieren, da dadurch Änderungen an einer der beiden Funktionen automatisch auf die andere Funktion übertragen werden.
Den Copy-Ctor über den Op= zu implementieren ist aber weniger sinnvoll, da in diesem Fall unnötig viel arbeit verrichtet wird. Der Copy-Ctor führt in diesem Fall erst eine Default-Initialisierung durch bevor der Op= dann die endgültigen Werte zuweist.
Von der Komplexität her ist der Copy-Ctor die einfachere Operation, da hier ein neues Objekt erzeugt wird. Man muss sich also z.B. keine Gedanken über bereits vorhandene Ressourcen machen. Und in der Regel baut man komplexere Operationen aus einfacheren zusammen. Nicht andersherum.Wenn ich ein Swap mache, bei dem ich garantiere, das er keine exception wirft, dann kann ich doch lieber gleich garantieren, das mein opeartor= nix wirft und spare mir die temporäre Copy-Instanz.
Natürlich kannst du deinen Op= auch ohne Swap exception-sicher machen. Der Vorteil von swap ist der den alle Funktionen haben: du lagerst bestimmten Code in eine Funktion aus und machst diesen Code damit für andere Funktionen zugänglich. Du musst den Code also nicht in jeder Methode neu schreiben.
Desweiteren verwendet die STL an einigen stellen std::swap. Hast du ein Swap in deiner Klasse, kannst du diese Funktion für deine Klasse einfach überladen (bzw. Spezialisieren), was in der Regel effizienter als der normale Dreieckstausch ist.
Der große Vorteil imo ist aber die Einfachheit der Implementation. Gerade bei komplexeren Hierarchien tendiert ein handgeschriebener Op= leicht zu Fehlern. Copy-und-Swap hingegen ist zwar nicht immer das Effizienteste, dafür kann man eigentlich dabei nicht viel falsch machen. Und richtiger Code ist immer erstmal wichtiger als schneller Code.
-
Volkard meinte in diesem alten Artikel:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-36357-and-highlight-is-sutter.html
,das ein Swap prinzipiell immer schick wäre. Ich verstehe nur nicht ganz, warum.
Ein richtig implementiertes swap ermöglicht die einfache Implementation vieler Techniken. Neben dem bereits genannten Copy-und-Swap-Trick verwende ich es z.B. am Häufigsten bei der Implementation von Transaktions-ähnlichen Operationen.
-
Danke, wenn das der olle Sutter auch so schön erklärt hätte, hätte ich nie fragen müssen.
Generell ist es richtig Copy-Ctor und Op= abhängig voneinander zu implementieren, da dadurch Änderungen an einer der beiden Funktionen automatisch auf die andere Funktion übertragen werden.
Naja, das ist doch eher selbstverständlich da "Don't repeat yourself" Allgemeingültigkeit besitzt.
-
TheBigW schrieb:
Volkard meinte in diesem alten Artikel:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-36357-and-highlight-is-sutter.html
,das ein Swap prinzipiell immer schick wäre. Ich verstehe nur nicht ganz, warum.ja, ein swap ist immer schick.
jede klasse, die einen kopierkonstruktor und einen zuweisungsoperator braucht, braucht doch bereits aus performancegründen auch ein swap.
denn wenn kopierkonstruktor und zuweisungsoperator gebaucht werden, dann ist keine flache kopie erwünscht, also passiert da irgendwas spannendes und teures, während ein swap (fast) immer billig ist.
man will ja auch mal std::sort benutzen, und das benutzt swap. für eine größere klasse ein eigenes swap haben und um faktor 100 schneller sein, das ist ein trick, den man nicht außer acht lassen sollte.
(ok, es geht auch anders, man könnte zeiger auf die objekte sortieren und danach in O(n) anhand der zeiger die objekte. nee, trotzdem, auch das ist dann schneller mit gutem swap. man könnte im container eh nur zeiger auf die objekte haben. aber die müßte man alle einzeln mit malloc-ähnlichem anlegen. nee. geht nicht fein ohne swap.)
aber auch, wenn man keinen sinn darin sieht, objekte der klasse in einen container zu stecken, kann man manchmal trotzdem swap anbieten, wenn es exceptionfreiheit (und automatisch performance) macht. ich kenne keine gute semantik für einen op= für ofstream. aber ich glaube, ein swap wäre klar. nur, wer will ostreams in einen container stecken? naja, ich mache es zur zeit. allerdings sehe ich noch keinen sinn in swap für ostreams, deswegen hab ich's auch nicht eingebaut.
ein swap kann auch wünschenswert sein, obwohl kopien nicht erlaubt sind! zum beispiel ein Stack, den will man nicht kopieren, weil's zu teuer ist. bei sowas verbiete ich kopieren erstmal, auch immer wieder als hinweis an mich, daß wenn ich es versuche, ich wohl einfach die falsche datenstruktur gewählt habe. aber ein swap ist vielleicht sinnvoll, wenn man einen algorithmus plant, wo eine liste von jobs abgearbeitet werden muss, aber manchmal ein job heute noch nicht geht, und auf die nächste runde vertagt werden muss. und wenn die runde fertig ist, macht man das, was nach einer und so passieren muss und swapt die stacks vor der nächsten runde. für algos dieser art sollten wohl alle datenstrukturen swap anbieten!
ok, sowas kann man umgehen, indem man zwei zeiger auf stacks hat, aber diese indirektion und das anlegen mit new und das sichern, daß man delete nicht vergisst, zum beispiel über auto_ptr, das wäre alles kram, den man mit einem swap schneller und einfacher besorgt.
ich mag zeiger nicht, aber ich mag swap.naja, und wenn wir und drauf geeinigt haben, daß ein swap schick ist, führt das auch zu sutters exceptionsicherem und schnellen op=.