================= Copy & Swap Idiom [TOC] ================= Wenn wir uns die letzte Fassung der _IntegerSequence_ ansehen, dann fällt uns auf, dass der Kopierkonstruktor und der Zuweisungsoperator einander ähneln. Auch zwischen dem _move constructor_ und dem _move assignment_ gibt es Gemeinsamkeiten. In beiden mit _rvalue_-Referenzen arbeitenden Fällen sind alle Komponenten auszutauschen, wobei beim _move constructor_ das "sterbende" Objekt in den Zustand gebracht wird, den auch der _default constructor_ liefern würde. Deswegen gibt es für C++ einen geschickten Ansatz zur Vereinfachung entsprechender Klassen, bei der die unnötige Doppelarbeit vermieden wird. Der funktioniert dahingehend, dass wir * im _copy constructor_ einmal definieren, wie kopiert wird und * in einer _swap_-Funktion einmal alle Komponenten zweier Objekte mit Hilfe der _swap_-Funktionen für die einzelnen Komponenten austauschen. Wir benötigen dann folgendes: * Einen _default constructor_, der ein "leeres" Objekt erzeugt. * Eine _swap_-Funktion, die keine Methode ist, aber innerhalb der Klasse als `friend` deklariert wird und somit uneingeschränkten Zugriff auch auf die privaten Komponenten hat. Diese Funktion erhält zwei Referenzen auf zwei Objekte und tauscht alle Komponenten untereinander aus. Die Funktion gibt keinen Wert zurück und erhält daher den Return-Typ `void`. * Einen _copy constructor_ wie gehabt, der in der Lage ist, ein Objekt vollständig zu klonen. * Einen _move constructor_, der im Initialisierungsteil (hinter dem ":" und vor der "{") ein "leeres" Objekt mit dem _default constructor_ erzeugt und dann im _compound statement_ (d.h. innerhalb von "{...}") die oben definierte _swap_-Funktion verwendet, um die Inhalte des "sterbenden" Objekts mit denen des eigenen, noch "leeren" Objekts austauscht. Beachten Sie hierbei, dass `this` ein Zeiger auf das eigene Objekt ist und somit `*this` eine Referenz auf das eigene Objekt. * Und schließlich nur noch einen einzigen Zuweisungsoperator, der ein anderes Objekt als Werteparameter erhält und eine Referenz auf das eigene Objekt zurückliefert. Beim Aufruf gibt es zwei denkbare Fälle: - Es wird eine _rvalue_ übergeben: Dann kann der lokale Werteparameter mit dem _move constructor_ erzeugt werden und so die Inhalte übernehmen, ohne dass sie kopiert werden. - Es wird eine _lvalue_ übergeben: Dann wird der lokale Werteparameter mit dem _copy constructor_ erzeugt und die Inhalte geklont, was in diesem Fall unvermeidlich ist. Somit wählt der Übersetzer in jedem Fall automatisiert die richtige Variante aus. Innerhalb der Funktion kann dann die _swap_-Funktion verwendet werden, um die Inhalte auszutauschen. Der lokale Werteparameter wird dann am Ende automatisch abgebaut. Aufgabe ======= Vereinfachen Sie die letzte Lösung entsprechend dem _copy and swap idiom_ in der oben beschriebenen Form und testen Sie Ihre Lösung wieder mit _valgrind_ und dem bereits zuvor eingesetzten Testprogramm. Vergleichen Sie die Ausgaben der Testprogramme. :import: session03/step05/IntegerSequence.hpp [fold] :import: session03/step05/test_is.cpp [fold] :navigate: up -> doc:index back -> doc:session03/page04 next -> doc:session03/page06