Am 14. September 2017 haben wir eine überarbeitete Fassung unserer Datenschutzrichtlinie veröffentlicht. Wenn Sie video2brain.com weiterhin nutzen, erklären Sie sich mit diesem überarbeiteten Dokument einverstanden. Bitte lesen Sie es deshalb sorgfältig durch.

C++ Grundkurs

Typen von Konstruktoren

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
C++ verfügt über verschiedene Typen von Konstruktoren. Dieses Video bietet einen detaillierten Überblick über die unterschiedlichen Arten.
07:30

Transkript

In dieser Lektion möchte ich Ihnen zwei besondere Konstruktoren in C++ vorstellen, den Copy- und den Move-Konstruktor. Beide Konstruktoren sind sehr ähnlich. Beide Konstruktoren erzeugen ein neues aus einem alten Objekt. Sie wenden aber ganz verschiedene Strategien an. Der Copy-Konstruktor kopiert die Attribute des alten Objektes in das neue hinein. Der Move-Konstruktor verschiebt die Attribute des alten Objektes in das neue. Nun gehe ich ein bisschen auf den Copy-Konstruktor ein. Der Copy-Konstruktor erwartet in der Regel eine konstante Referenz auf ein Objekt und erzeugt damit ein neues Objekt. Das sehen Sie hier. Eine konstante Referenz mit dem Namen a und erzeugt damit ein neues Objekt. Der Copy-Konstruktor wird in der Regel vom Compiler erzeugt. Er wird aber nicht erzeugt, wenn die Klasse einen Move-Konstruktor oder einen Move- Zuweisungsoperator besitzt. Noch eine Warnung. In sehr vielen Kontexten benötigt der Compiler einen Copy-Konstruktor, um automatisch Objekte zu kopieren oder neue Objekte aus bestehenden zu initialisieren. Besitzt Ihre Klasse solch einen Konstruktor nicht, gibt es natürlich einen Kompilierfehler. Nun gehe ich auf den anspruchsvolleren Move-Konstruktor ein. Move-Konstruktor sind Konstruktoren, die nicht konstante Rvalue-Referenzen auf der Instanz einer Klasse erwarten. Das sehen Sie hier. Nicht konstant, hier fehlt das const und das ist eine Rvalue-Referenz. Sie verschieben das ursprüngliche Objekt in das zu instanziierende Objekt. Der Compiler wendet immer dann einen Move-Konstruktor an, wenn er weiß, dass es zulässig ist. Zulässig ist es dann, wenn er ein neues Objekt aus meinem alten Objekt erzeugen kann und er weiß, dass das alte Objekt nicht mehr benötigt wird. Die ganz große Idee dahinter ist einfach, er vermeidet dadurch unnötiges Kopieren. Ein Move-Konstruktor, wenn Sie ihn implementieren, sollte einer gewissen Strategie folgen. Es sollen also gewisse Schritte ausgeführt werden. So passiert es in der Standard Template Library und so sollten auch Ihre eigenen Move-Konstruktoren sein, wenn Sie einen implementieren. Das sind drei Schritte, die Sie tun sollten. Als erstes sollten Sie die Attribute des neuen Objektes setzen, dann den Inhalt des alten Objektes in das neue hinein schieben und zuletzt die Attribute des alten Objekt auf ihre Default-Werte setzen. Da stellt sich natürlich die Frage, wann wird ein Move-Konstruktor erzeugt? Der wird dann erzeugt, wenn alle Attribute einer Klasse und auch ihre Basisklasse einen Move-Konstruktor besitzen. Er wird nicht erzeugt, wenn eine Klasse bereits einen Copy-Konstruktor, Copy-Zuweisungsoperator, Move-Zuweisungsoperator oder Destruktor besitzt. Besitzt eine Klasse beides, also Move-Konstruktor und einen Copy-Konstruktor, besitzt der Move-Konstruktor Vorrang. Nun gehe ich noch auf ein paar Begriffe ein. Als erstes besitzt eine Klasse einen Copy-Konstruktor, sollte sie auch einen Copy-Zuweisungsoperator anbieten. Damit verhält sich die Klasse einfach symmetrisch. Das Gleiche gilt für einen Move-Konstruktor und Move-Zuweisungsoperator. Dann gibt es noch den Begriff der Copy- und der Move-Semantik. Wenn eine Klasse einen Copy-Konstruktor und einen Copy- Zuweisungsoperator anbietet, unterstützt sie die Copy-Semantik. Wenn Sie einen Move-Konstruktor und einen Move-Zuweisungsoperator anbietet, unterstützt sie die Move-Semantik. Das ist vorhanden in den Containern der Standard Template Library und im std::string. Die bieten sowohl die Copy- als auch die Move-Semantik an. Nun zeige ich Ihnen noch die ganze Theorie. Hier eine einfache Klasse. Sie sehen die Klasse Account hier. Die hat einen Konstruktor, einen Default-Konstruktor, der verwendet wird, um balance auf 0 zu initialisieren. Dann hat sie noch zwei weitere Konstruktoren, den Copy-Konstruktor hier und den Move-Konstruktor hier. Beide geben als erstes ihre Signatur aus. Das ist die Signatur des Copy- und das ist die Signatur des Move-Konstruktors. Dann initialisieren sie sich selbst. Der Copy-Konstruktor macht das, indem er other.balance verwendet, um balance zu initialisieren. Der Move-Konstruktor macht hier das Gleiche, setzt aber danach noch other.balance auf 0, sprich auf den Default-Wert. Hier unten wende ich den Copy- und Move-Konstruktor an. Um ihn anwenden zu können, brauche ich natürlich ein Objekt, mit dem ich ein neues Objekt initialisieren kann. Hier verwende ich also Account und in diesem Schritt wende ich einen Copy-Konstruktor und in diesem Schritt wende einen Copy-Konstruktor an. Das sieht man schön hier bei der Ausgabe. Hier sehen Sie, das ist der Copy-Konstruktor, den ich hier anwende. Hier und hier. Verwende ich aber std::move, das ist ein Algorithmus der Standard Template Library, um explizit einen Move-Konstruktor aufzurufen, dann wird hier auch der Move-Konstruktor verwendet. Zugegeben, das Programm war relativ einfach und es ist vermutlich auch nicht 100-prozentig klar, wieso man eigentlich einen Move-Konstruktor haben will. Das will ich aber mit dem nächsten Beispiel motivieren. Das Beispiel ist ein Stückchen anspruchsvoller. Hier habe ich wieder die Klasse Account. Die Klasse Account soll eine große Menge von deposits besitzen. Wie viel depostis, das wird hier im Konstruktor übermittelt und dann erzeuge ich einfach ein Array von doubles und jeder double-Wert soll ein deposit repräsentieren. Um Accounts zu kopieren, biete ich den Copy-Konstruktor und den Move-Konstruktor an. Zuerst zum Copy-Konstruktor, der bekommt eine const-Referenz und verwendet die const-Referenz, um die Anzahl seiner deposits zu initialisieren mit other.numberOf und das ist das wirklich Anspruchsvollere, um ein Array von desposits anzulegen. Das geschieht hier. Hier besorge ich mir den Speicher und hier kopiere ich alle deposits in mein Account, vom ersten bis zum letzten nach deposits. Das war der Copy-Konstruktor im Gegensatz zum Move-Konstruktor. Der schaut einfacher aus. Was mache ich im Move-Konstruktor? Ich setzte die Anzahl der deposits auf die von other und ich verbiege den Zeiger, der auf das Array von deposits zeigt auf das alte deposits. Zum Schluss setze ich das alte deposits auf 0 und sage auch, es gibt kein deposits mehr. Jetzt wende ich das Ganze an, dann sehen Sie sehr gut, dass der Move-Konstruktor in diesem Fall deutlich schneller ist wie der Copy-Konstruktor. Hier will ich einfach, dass die Zahlen nicht in der exponential Schreibweise ausgegeben werden und hier setze ich die Nachkommastellen auf 10. Ich fange wieder an mit Account, der, wenn ich es richtig abgezählt habe, 100 000 000 deposits besitzen soll. Natürlich eine große Zahl. Diesen Account verwende ich, um einen neuen Account zu erzeugen. Das erste Mal mit dem Copy-Konstruktor und das zweite Mal mit dem Move-Konstruktor. Sie sehen hier std::move. Was ich jetzt noch mache, ist einfach zu messen, wie lange beides dauert. Hier bestimme ich die aktuelle Uhrzeit. auto start = std::chrono::system_clock::now() Konstruiere das neue Objekt aus dem alten Objekt. Bestimme nochmals die aktuelle Uhrzeit. Ziehe die Ursprungsuhrzeit ab und bekomme als Ergebnis, wie lange dieses Erzeugen des Account1 gedauert hat. Das Gleiche mache ich hier auch. In diesem Fall aber für Account1 und natürlich wende ich hier einen Move-Konstruktor an. Wenn ich das jetzt ausführe, sehen Sie hier, der Performance-Unterschied ist gewaltig. Ich kann es eigentlich gar nicht richtig darstellen. Hier brauche ich nahezu eine Sekunde und hier kann ich es noch gar nicht mal messen. In dieser Lektion habe ich Ihnen den Move- und den Copy-Konstruktor vorgestellt. Beide sind sehr wichtige Konstruktoren in C++. Beide tun etwas sehr ähnliches. Sie erzeugen neues aus einem bestehenden Objekt. Der große Unterschied ist aber, der Copy-Konstruktor kopiert die Elemente vom alten ins neue Objekt, der Move-Konstruktor verschiebt die Elemente vom alten ins neue Objekt. Für große Objekte kann der Move-Konstruktor einen sehr großen Performance- Gewinn mit sich bringen.

C++ Grundkurs

Steigen Sie in die mächtige Programmiersprache C++ ein und lernen Sie dabei alle wichtigen Funktionen mit Anwendungsbeispielen kennen.

8 Std. 14 min (147 Videos)
Derzeit sind keine Feedbacks vorhanden...
 

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!