Meeting C++ C++11 R-Value Referenzen



Ähnliche Dokumente
Vorkurs C++ Programmierung

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Java: Vererbung. Teil 3: super()

Java Kurs für Anfänger Einheit 5 Methoden

Was meinen die Leute eigentlich mit: Grexit?

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

Zählen von Objekten einer bestimmten Klasse

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Objektorientierte Programmierung

Objektorientierte Programmierung. Kapitel 12: Interfaces

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Arbeiten mit UMLed und Delphi

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 22

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

Software Engineering Klassendiagramme Assoziationen

Einführung in die Programmierung

Folge 19 - Bäume Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Erstellen einer Collage. Zuerst ein leeres Dokument erzeugen, auf dem alle anderen Bilder zusammengefügt werden sollen (über [Datei] > [Neu])

Folge 18 - Vererbung

5. Abstrakte Klassen

Grundlagen von Python

Zwischenablage (Bilder, Texte,...)

Die Post hat eine Umfrage gemacht

Informatik 2 Labor 2 Programmieren in MATLAB Georg Richter

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Einführung in die Java- Programmierung

Objektorientierte Programmierung

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

SEP 114. Design by Contract

Software Engineering Interaktionsdiagramme

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Grundbegriffe der Informatik

C++ - Operatoren. Eigene Klassen mit neuen Funktionen

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Programmieren in Java

Objektorientierte Programmierung mit C++ Vector und List

Zeichen bei Zahlen entschlüsseln

MORE Profile. Pass- und Lizenzverwaltungssystem. Stand: MORE Projects GmbH

Das große ElterngeldPlus 1x1. Alles über das ElterngeldPlus. Wer kann ElterngeldPlus beantragen? ElterngeldPlus verstehen ein paar einleitende Fakten

Adobe Photoshop. Lightroom 5 für Einsteiger Bilder verwalten und entwickeln. Sam Jost

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

Software Engineering Klassendiagramme Einführung

Leit-Bild. Elbe-Werkstätten GmbH und. PIER Service & Consulting GmbH. Mit Menschen erfolgreich

Das Persönliche Budget in verständlicher Sprache

Objektbasierte Entwicklung

Thema: Winkel in der Geometrie:

Eva Douma: Die Vorteile und Nachteile der Ökonomisierung in der Sozialen Arbeit

Würfelt man dabei je genau 10 - mal eine 1, 2, 3, 4, 5 und 6, so beträgt die Anzahl. der verschiedenen Reihenfolgen, in denen man dies tun kann, 60!.

Primzahlen und RSA-Verschlüsselung

Bauteilattribute als Sachdaten anzeigen

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen.

Einführung in die Programmierung

Leichte-Sprache-Bilder

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

Computeranwendung und Programmierung (CuP)

In diesem Tutorial lernen Sie, wie Sie einen Termin erfassen und verschiedene Einstellungen zu einem Termin vornehmen können.

Excel Funktionen durch eigene Funktionen erweitern.

Viele Bilder auf der FA-Homepage

5. Tutorium zu Programmieren

Javakurs 2013 Objektorientierung

Updatehinweise für die Version forma 5.5.5

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

Unterprogramme. Funktionen. Bedeutung von Funktionen in C++ Definition einer Funktion. Definition einer Prozedur

.procmailrc HOWTO. zur Mailfilterung und Verteilung. Stand:

Installationsanleitung Maschinenkonfiguration und PP s. Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18.

Der Vollstreckungsbescheid. 12 Fragen und Antworten

Professionelle Seminare im Bereich MS-Office

Die neue Aufgabe von der Monitoring-Stelle. Das ist die Monitoring-Stelle:

Einführung in die Java- Programmierung

Wir machen neue Politik für Baden-Württemberg

Zahlenwinkel: Forscherkarte 1. alleine. Zahlenwinkel: Forschertipp 1

2. Semester, 2. Prüfung, Lösung

M. Graefenhan Übungen zu C. Blatt 3. Musterlösung

Outlook-Daten komplett sichern

Abschlussprüfung Realschule Bayern II / III: 2009 Haupttermin B 1.0 B 1.1

Warum Sie jetzt kein Onlinemarketing brauchen! Ab wann ist Onlinemarketing. So finden Sie heraus, wann Ihre Website bereit ist optimiert zu werden

Algorithmen und Datenstrukturen

Beschreibung Regeln z.b. Abwesenheitsmeldung und Weiterleitung

Gutes Leben was ist das?

Programmierkurs Java

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software

Welchen Nutzen haben Risikoanalysen für Privatanleger?

Karten-Freischaltung mit dem UNLOCK MANAGER

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Nicht über uns ohne uns

Innere Klassen in Java

13 OOP MIT DELPHI. Records und Klassen Ein Vergleich

Objektorientierte Programmierung mit C++ Zusammenfassung der wichtigsten Topics rund um die objektorientierte Programmierung mit C++11

Urlaubsregel in David

Anleitung über den Umgang mit Schildern

Was bedeutet Inklusion für Geschwisterkinder? Ein Meinungsbild. Irene von Drigalski Geschäftsführerin Novartis Stiftung FamilienBande.

Studentische Lösung zum Übungsblatt Nr. 7

Diplomarbeit. Konzeption und Implementierung einer automatisierten Testumgebung. Thomas Wehrspann. 10. Dezember 2008

Unterrichtsmaterialien in digitaler und in gedruckter Form. Auszug aus:

Transkript:

Meeting C++ Detlef Wilkening http://www.wilkening-online.de 09.11.2012 Inhalt Motivation L-Values und R-Values R-Value Referenzen Move Semantik std::move Funktionen mit R-Value-Referenz Parametern Fazit Fragen 1

Motivation Einer der Haupt-Performance Probleme in C++ sind Kopien Überflüssige Kopien An vielen Stellen werden Kopien erzeugt Auch viele Stellen, an denen es der Einsteiger nicht erwartet Und Kopien können teuer sein Beispiele: Zeichenketten-Literal in Vektor rein pushen Vektor Reallokation Swap Funktion String Addition 2

Zeichenketten-Literal in Vektor rein pushen vector<string> v; v.push_back("c++"); Vektor Reallokation 3

Swap Funktion 1/6 Typische alte Implementierung Bilder siehe folgende 5 Folien void swap(t& lhs, T& rhs) T temp(lhs); lhs = rhs; rhs = temp; Swap Funktion 2/6 4

Swap Funktion 3/6 Swap Funktion 4/6 5

Swap Funktion 5/6 Swap Funktion 6/6 C + + B o o s t B o o s t string string C + + swap( string& lhs, string& rhs ) C + + string temp 6

String Addition 1/2 Bild siehe nächste Folie string operator + (const string&, const string&); string operator + (const string&, const char*); string s1("s1"); string s2("s2"); string s = s1 + "und" + s2; String Addition 2/2 7

Alle diese Beispiele zeichnen sich dadurch aus: Das Kopien angelegt werden Und die Kopien unter Umständen sehr teuer sind Z.B. bei Containern, Strings, Und die Kopien eigentlich gar nicht notwendig sind Warum sind die Kopien nicht notwendig? Die Originale werden danach gelöscht Effizienter wäre es, wenn man ihren Inhalt einfach "weiterverwenden" und/oder "moven" hätte können Siehe Bilder auf den nächsten Folien Zeichenketten-Literal in Vektor rein pushen Der Performance-Traum vom Moven vector<string> v; v.push_back("c++"); 8

Vektor Reallokation Der Performance-Traum vom Moven Swap Funktion 1/5 Bilder vom Move Performance-Traum auch auf den nächsten Folien 9

Swap Funktion 2/5 Swap Funktion 3/5 10

Swap Funktion 4/5 Swap Funktion 5/5 11

String Addition Der Performance-Traum vom Moven string s = s1 + "und" + s2; Wann macht moven Sinn? Die logischen Objekte haben Daten ausserhalb liegen Ausserhalb dem primären Speicherbereichs des Objektes Diese Daten müssen synchron zum Objekt gehandelt werden Typische Anzeichen für diese Objekte: Destruktor Kopier-Konstruktor Kopier-Zuweisungs-Operator Also: Regel der 3 Bei Objekten, die z.b. nur aus int bestehen, ist moven wie kopieren 12

L- und R-Values Was sind L-Values und R-Values? Es gibt eine einfache und eine exaktere Erklärung Zuerst die einfache Erklärung Sie reicht für viele Dinge quasi als Pi*Daumen Regel Alles was auf der linken Seite einer Zuweisung stehen kann, ist ein L-Value, der Rest ist ein R-Value. int n, n1, n2; n = n1 + n2; // Okay, n ist ein L-Value 3 = n1 + n2; // Fehler 3 ist R-Value 13

L-Values sind Objekte, die nach dem Anweisungs-Ende noch existieren Variablen, aber auch z.b. dereferenzierte Zeiger Elemente in Arrays oder Containern Funktions-Aufrufe, die eine Referenz zurückgeben, z.b. vector[idx], ++n R-Values sind Objekte, die nach dem Anweisungs-Ende (Semikolon) nicht mehr da sind Literale, z.b. 42 Funktions-Aufrufe, die eine Kopie zurückgeben, z.b. s1+s2, n++ Temporäre Objekte, z.b. string("temp") Hilfsregeln Hat es einen Namen? Wenn ja, dann ist es ein L-Value Wenn nein, dann ist es vielleicht ein R-Value Kann man die Adresse davon bekommen? Wenn ja, dann ist es ein L-Value Wenn nein, dann ist es ein R-Value Der Standard sagt: Die Adresse eines persistenten Objekts ist sinnvoll Die eines temporären Objekts ist gefährlich Achtung dies heißt nicht, dass man nicht über Tricks an die Adresse kommen kann. Aber eben nicht durch direkte Anwendung von & Oder temporäre Objekte nicht explizit ändern kann 14

Hinweis schon mal für später (Perfect Forwarding): Objekte mit Namen sind L-Values Also sind auch R-Value Referenz Variablen L-Values, denn sie haben einen Namen! R-Value Referenzen 15

R-Value Referenzen sind Referenzen, die an R-Values binden können Werden mit && definiert Es sind weiterhin normale Referenzen Müssen initialisiert werden Sind abhängig, dass die referenzierten Objekte lange genug leben Es kann const R-Value Referenzen geben Sind aber sehr ungewöhnlich Aber sie binden eben an R-Values Die alten C++03 Referenzen heißen nun L-Value Referenzen Non-Const L-Value Referenzen können nicht an R-Values binden void fct(string&); fct("c++"); // Fehler, da R-Value void fct(const string&); fct("c++"); // okay void fct(string&&); fct("c++"); // okay 16

L- und R-Values haben ein unterschiedliches Verhalten bei Der Initialisierung Beim Überladen Initialisierung Welche Referenz bindet an welche Values? & const & && const && L-Value x x x x const L-Value x x R-Value x x x const R-Value x x Zwei einfache Regeln Const muß respektiert werden Kein versehentliches Ändern von temporären Objekten 17

string mod_lval("c++"); const string const_lval("boost"); string mod_rval() return "STL"; const string const_rval() return "R-Value"; string& lr1 = mod_lval; string& lr2 = const_lval; string& lr3 = mod_rval(); string& lr4 = const_rval(); // Okay // Fehler // Fehler // Fehler const string& clr1 = mod_lval; const string& clr2 = const_lval; const string& clr3 = mod_rval(); const string& clr4 = const_rval(); // Okay // Okay // Okay // Okay 18

string&& rr1 = mod_lval; string&& rr2 = const_lval; string&& rr3 = mod_rval(); string&& rr4 = const_rval(); // Okay // Fehler // Okay // Fehler const string&& crr1 = mod_lval; const string&& crr2 = const_lval; const string&& crr3 = mod_rval(); const string&& crr4 = const_rval(); // Okay // Okay // Okay // Okay Überladen Welche Funktion wird von welchem Wert aufgerufen 2 Situationen Alle 4 Varianten überladen Diese Situation hat mehr theoretischen Wert Nur 2 Varianten überladen (const L-Value und R-Value Referenz) Dies ist die typische Situation in der Praxis 3 Regeln: L-Values binden lieber an L-Value Referenzen R-Values binden lieber an R-Value Referenzen Const muß respektiert werden 19

string mod_lval("c++"); const string const_lval("boost"); string mod_rval() return "STL"; const string const_rval() return "R-Value"; void overload(string& s)... void overload(const string& s)... void overload(string&& s)... void overload(const string&& s)... overload(mod_lval); overload(const_lval); overload(mod_rval); overload(const_rval); // => overload(string&) // => overload(const string&) // => overload(string&&) // => overload(const string&&) 20

void overload(const string& s)... void overload(string&& s)... overload(mod_lval); overload(const_lval); overload(mod_rval); overload(const_rval); // => overload(const string&) // => overload(const string&) // => overload(string&&) // => overload(const string&) Praktische Variante überladen auf const & && Nur modifizierbare R-Values binden an R-Value Referenzen Alles anderen Argumente binden an L-Value Referenzen Aber die modifizierbaren R-Values sind ja auch die, die überflüssige Kopien sind Die Regeln erlauben das Erkennen überflüssige Kopien durch den Compiler (zumindest zum Teil z.b. swap nicht) Dies ist die Grundlage der Move-Semantik 21

Noch eine Regel, bevor es weitergeht... Wenn Funktionen Wert-Rückgaben (Kopien) machen Dann sind dies überflüssige Kopien Wenn die Funktionen "const Typ" zurückgeben, dann bindet das nicht an R-Value Referenzen Dann kann keine Move-Semantik zuschlagen => Also sollten Funktionen nie Const-Wert-Rückgaben machen Move Semantik 22

Wie implementiert man nun eine Move-Semantik? Erkennen können wir Moveable Objekte durch R-Value Referenzen Implementiert werden muß: Move-Konstruktor Move-Zuweisungs-Operator = Beispiel Klasse mit einem dynamisch allokierten Integer Nicht sehr realistisch, aber schön einfach Realistisch wäre z.b. eine String-Klasse Auf den folgenden Folien: Erstmal die normale Implementierung Ohne Smart-Pointer, schön einfach Dann die Move-Semantik class DynamicInteger public: explicit DynamicInteger(int arg=0); DynamicInteger(const DynamicInteger& other); DynamicInteger& operator=(const DynamicInteger& other); ~DynamicInteger(); private: ; int* p; 23

DynamicInteger::DynamicInteger(int arg) p = new int(arg); DynamicInteger::DynamicInteger(const DynamicInteger& other) if (other.p) p = new int(*other.p); else p = 0; 24

DynamicInteger& DynamicInteger::operator=(const DynamicInteger& other) if (this==&other) return *this; delete p; // Hier könnte man p weiterverenden... // aber es geht um s Prinzip if (other.p) p = new int(*other.p); else p = 0; return *this; DynamicInteger::~DynamicInteger() delete p; 25

DynamicInteger create(int arg) return DynamicInteger(arg); // Mit RVO int main() // Int-Konstruktor mit 0 // Int-Konstruktor mit 42 DynamicInteger d1; // Kopier-Zuweisungs-Operator 42 d1 = create(42); // Destruktor: 42 // Destruktor: 42 Und nun zusätzlich mit Move-Semantik 26

class DynamicInteger public: explicit DynamicInteger(int arg=0); DynamicInteger(const DynamicInteger& other); DynamicInteger(DynamicInteger&& other); DynamicInteger& operator=(const DynamicInteger& other); DynamicInteger& operator=(dynamicinteger&& other); ~DynamicInteger(); private: int* p; ; DynamicInteger::DynamicInteger(DynamicInteger&& other) p = other.p; other.p = 0; 27

DynamicInteger& DynamicInteger::operator=(DynamicInteger&& other) if (this == &other) return *this; delete p; p = other.p; other.p = 0; return *this; DynamicInteger create(int arg) return DynamicInteger(arg); // Mit RVO int main() // Int-Konstruktor mit 0 // Int-Konstruktor mit 42 DynamicInteger d1; // Move-Zuweisungs-Operator 42 d1 = create(42); // Destruktor: null // Destruktor: 42 28

Move-Semantik Das Ziel-Objekt stiehlt beim moven die Daten vom Quell-Objekt und nullt sie Der Destruktor des Quell-Objektes hat dann nichts mehr zu tun. Achtung Der Move-Zuweisungs-Operator benötigt wie auch der Kopier-Konstruktor Überprüfung auf Zuweisung auf sich selbst Move-Konstruktoren und Move-Zuweisungs-Operatoren sollen keine Exceptions werfen Dies ist machbar, da man ja nur elementare und Zeiger-Typen verschiebt Nutzen Sie in C++11 das neue Schlüsselwort noexcept Automatische Erzeugung von Funktionen Die Regeln für die automatische Erzeugung von Funktionen (implizite Funktionen) werden vom Move-Konstruktor und dem Move-Zuweisungs- Operator nur bzgl. implizitem Standard-Konstruktor beeinflußt: Move-Konstruktor und Move-Zuweisungs-Operatoren werden niemals implizit erzeugt Jeder manuelle Konstruktor verbietet den automatischen Standard- Konstruktor auch der Move-Konstruktor. Der implizite Kopier-Konstruktor wird nicht vom Move-Konstruktor beeinflußt Sondern weiterhin nur durch manuelle Kopier-Konstruktoren Der implizite Kopier-Zuweisungs-Operator wird nicht vom Move- Zuweisungs-Operatore beeinflußt Sondern weiterhin nur durch den manuellen Kopier-Zuweisungs-Operator 29

std::move Okay, Literal per push_back in den Vektor ist jetzt effizient Aber was ist mit swap? Die überflüssige Kopie ist nicht weg! void swap(t& lhs, T& rhs) T temp(lhs); lhs = rhs; rhs = temp; 30

Problem lhs und rhs sind L-Values L-Values werden kopiert Move-Semantik kann nicht zuschlagen Lösung Mache L-Value explizit zu R-Value Wenn Move-Semantik vorhanden => dann wird gemovt Wenn keine Move-Semantik => dann wird kopiert R-Values binden auch an Const L-Value-Referenzen void swap(t& lhs, T& rhs) T temp(lhs); lhs = rhs; rhs = temp; Explizit L-Values zu R-Values machen std::move Aber Achtung das Quell-Objekt wird genullt Es ist hinterher also leer Hinweis statt move geht auch static_cast<src&&>(src); void swap(t& lhs, T& rhs) T tmp(std::move(lhs)); lhs = std::move(rhs); rhs = std::move(tmp); 31

std::move ist die Lösung für explizites Moven Immer wenn Sie moven könnten, falls Move-Semantik implementiert ist und sie ein L-Value haben Nutzen Sie std::move Aus dem Header <utility> Jetzt wissen wir auch, wie man Move-Semantik für Klassen mit Move-Semantik Attributen implementiert Der Compiler erzeugt nie Move-Funktionen Move-Konstruktor Move-Zuweisungs-Operator Move-Semantik muß immer manuell programmiert werden Klasse mit Movable-Member sollten selber movable sein Move-Semantik manuell implementieren 32

class DynamicPoint public: DynamicPoint(int xarg, int yarg) : x(xarg), y(yarg) DynamicPoint(DynamicPoint&& other); DynamicPoint& operator=(dynamicpoint&& other); // Weiteres... private: DynamicInteger x; DynamicInteger y; ; DynamicPoint::DynamicPoint(DynamicPoint && other) : x(std::move(other.x)), y(std::move(other.y)) DynamicPoint& DynamicPoint::operator=(DynamicPoint && other) x = std::move(other.x); y = std::move(other.y); return *this; 33

R-Value-Referenz Parameter Benötigt man R-Value Referenzen für Funktions-Parameter? Eher selten Meist reicht es, sich auf auf die Move-Semantik der Klassen zu verlassen Außer Ihre Funktion kann einen Vorteil aus dem expliziten Gebrauch von modifizierbaren R-Values ziehen. Beispiel: String-Addition Hier z.b. die Addition von temp(sl+ und ) und sr. string s, sl, sr; s = sl + "und" + sr; 34

string operator+(const string&, const string&); string operator+(const string&, const char*); string operator+(string&& lhs, const string& rhs) lhs += rhs; return lhs; // Nutzt lhs statt neuen String anzulegen string s, sl, sr; s = sl + "und" + sr; 35

Und R-Value-Referenzen als Funktions-Rückgaben? Tendenziell eher nicht sinnvoll Auch R-Value-Referenzen sind Referenzen Probleme mit der Lebensdauer sind vorprogrammiert Eher auf RVO, NRVO und Move-Semantik verlassen Aber prinzipiell möglich ist es Vielleicht gibt es wirklich Sonder-Sonder-Sonderfälle, wo das sinnvoll ist Fazit 36

Was fehlte? Viele Details Vor allem aber Perfect Forwarding Perfect Forwarding Ermöglicht in Funktions-Template die optimale Weiterleitung von Argumenten Const L-Value Referenz L-Value Referenz R-Value Referenz Der Compiler sucht nach Regeln die richtige Referenz aus Ermöglicht perfekte Factory Funktionen R-Value Referenzen sind nicht ganz trivial, aber R-Value Referenzen sind ein großer Schritt Kopien zu vermeiden Die C++11 Standard-Bibliothek nutzt sie überall Ein Umstieg auf C++11 bringt häufig schon einen Performance-Boost Spezielle Programme bringen es locker auf einen Faktor 10 Normale reale Programme von mir liegen zwischen Faktor 1 bis 1,8 37

Bibliotheks-Entwickler sollten R-Value Referenzen beherrschen und nutzen Move-Semantik in Bibliotheks-Klassen ermöglicht transparente Nutzung Für Einsteiger gibt es sicher wichtigere Themen C++ ist groß und hat viele wichtige Themen Aber schon der professionelle Programmierer sollte sie kennen Move-Semantik in eigene Klassen einbringen std::move nutzen Perfect-Forwarding in Factory-Funktionen Fragen? 38