9.2012 windows phone phone · 66.net-sprachen. c++11 9.2012 von thomas trotzki und christian binder...

10
www.windowsdeveloper.de Deutschland 9,80 € Österreich 10,80 € Schweiz 19,50 sFr 9.2012 Sessions der BASTA! 2012 und der MobileTech Con im Heft! TFS 12 Express Teil 1: ALM ohne Kosten und Mühen 56 Workflow Foundation 4.5 Versionierte Workflows und Contract-First 44 . . . . . . . Modern C++11 Teil 1: Die neuen Leistungsmerkmale 66 Datenbank to go 18 Lokale Datenbanken unter WP 7.5 Twitter-API 25 Twitter-Integration auf WP 7 Bing-Maps-API 12 Standortbezogene Apps Windows Phone

Upload: others

Post on 31-Aug-2019

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

www.windowsdeveloper.de

Deutschland 9,80 €Österreich 10,80 €Schweiz 19,50 sFr

9.2012

Sessions der BASTA! 2012 und der MobileTech Con im Heft!

TFS 12 Express

Teil 1: ALM ohne Kosten und Mühen

56

Work� ow Foundation 4.5 Versionierte Workfl ows und Contract-First

44

window

s.develop

er 9.20

12

Win

dows P

hon

e . TFS . X

box . WF 4

.5 . XA

ML . C+

+ . CSI . C#

0800 186 07 06Vertriebs-Hotline:

/update/2012/09

Hauptsitz in den USA ComponentSource650 Claremore Prof WaySuite 100WoodstockGA 30188-5188USA

Zahlungen auf Rechnung und per Inlandsüberweisung auch gerne angenommen.

Hauptsitz in Europa ComponentSource30 Greyfriars RoadReadingBerkshireRG1 1PE Großbritannien

Hauptsitz in Japan ComponentSource3F Kojimachi Square Bldg3-3 Kojimachi Chiyoda-kuTokyoJapan102-0083 www.componentsource.com

www.componentsource.com

© 1996-2012 ComponentSource. Alle Rechte vorbehalten. Alle Preise waren zum Zeitpunkt der Veröffentlichung dieses Dokuments korrekt. Online-Preise können sich aufgrund von Schwankungen und online angebotenen Preisnachlässen ändern.

Meistgekauftes #1 ComponentSource Produkt - Ein komplettes Angebot mit Präsentations-Controls und Reporting-Lösungen für WinForms-, ASP.NET-, Silverlight- und WPF-Anwendungen.

• Erwecken Sie Ihre Software mit intelligenten Touch-basierte Anwendungen zum Leben

• Nutzen Sie Ihre vorhandenen Entwicklungsfähigkeiten, um die wachsende Nachfrage nach überwältigenden touch-fähigen Apps auf allen Plattformen, einschließlich WinForms, WPF und ASP.NET, zu erschließen

• Stellen Sie sich Business-Anwendungen für die Windows 8 Metro Entwurfsästhetik neu vor

• Wende Sie anspruchsvolle Designs an oder kreieren Sie Ihre eigenen und integrieren Sie Ihre Unternehmensmarke

• Integrieren Sie Offi ce-inspirierte und Business Intelligence-Dashboards in Ihr Design

• Lassen Sie Benutzer die Daten in überzeugender Weise ansehen und bearbeiten

• CodeRush hilft Ihnen, Ihre komplexe Code-Basis zu erstellen und zu verwalten, so dass mehr Zeit auf Ihrer Geschäftslogik fokussiert werden kann

• Wählen Sie eine einzelne Plattform oder erhalten Sie mehr mit Universal oder Enterprise-Abonnements

Mehr über DXperience und preisgekrönte DevExpress-Produkte unter:www.componentsource.com/features/devexpress

DXperience DXv2 12.1 ab 1.424 € inkl. MwStBEST-SELLER

Essential Studio Enterprise Edition ab 1.895 € inkl. MwSt

Benutzerober� äche, Reporting und BI-Komponente - alles in einem Paket.

• Angepasster XlsIO Pivot-Engine & neuer WinForms PivotGrid-Control

• Enthält erweiterten Projektassistenten für ASP.NET MVC

• Unterstützung für Windows-Phone-7, Android, iPhone, iPad und Blackberry-Geräte

• Einmal geschrieben und Sie können auf mehrere Plattformen für mobile Geräte verteilen!

• Jetzt mit Visual Studio 2011 Beta kompatibel

BEST-SELLER

ActiveReports Developer 7 ab 664 € inkl. MwSt

Die schnelle und � exible Reporting-Engine ist jetzt noch besser geworden.

• Neuer Seiten-Layout-Designer - bietet präzise Design-Tools für die komplexeste Form von Berichten z.B. Steuern, Versicherungen und Investitions-Formularen, etc.

• Mehr Steuerelemente - aktualisierte Tabellensteuerelemente, Barcode, Matrix und Kalender sowie Daten-Visualisierungs-Features

• Mehr Anpassungsoptionen - neugestaltete Viewer- und Designer-Steuerelemente

BEST-SELLER

Modern C++11

Teil 1: Die neuen Leistungsmerkmale

66

Datenbank to go 18Lokale Datenbanken unter WP 7.5

Twitter-API 25Twitter-Integration auf WP 7

Bing-Maps-API 12Standortbezogene Apps

WindowsPhone

Page 2: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

66

.net-sprachen . C++11

9.2012

von Thomas Trotzki und Christian Binder

C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern. Doch die Nor-mierung der weit verbreiteten Sprache nimmt immer wieder eine recht lange Zeit in Anspruch. So musste auch auf C++11 zwölf Jahre gewartet werden. Zwar wurde bereits 2003 mit TR1 (auch C++03 genannt) ein Zwischenstand als Draft vorgelegt, an dem sich

die Compilerhersteller orientieren konnten, endgültig verabschiedet wurde dieser aber nicht. Sicherlich wird aber noch einige Zeit vergehen, bis alle Features auch in jedem kommerziellen C++-Compiler Umsetzung gefunden haben werden. GNU als Open Source hat hier die Nase vorn. Das Warten auf C++11 hat sich aber gelohnt, stehen nun doch neue Leistungsmerk-male zur Verfügung, die die Lücke zwischen C++ und Sprachen wie Java oder C# in weiten Bereichen schlie-ßen können. Die großen Highlights stellen zweifelsoh-ne Lambdas dar, die auch für die ebenfalls normierte Standardbibliothek STL ganz neue Möglichkeiten er-öffnet haben. Aber auch andere neue Schlüsselworte, wie auto, override und � nal � nden in diesem Artikel Beachtung. Doch beginnen wir zunächst mit einigen kleineren Neuerungen.

Artikelserie

Teil 1: Modern C++11Teil 2: Going Parallel with C++Teil 3: ALM for C++

Teil1: Modernes C++11

Was lange währt, wird endlich wahr

Im Herbst vergangenen Jahres wurde C++11, der Nachfolger des bisherigen Standards C++99, verabschiedet. Zahlreiche Compilerhersteller sind nun eifrig damit beschäftigt, die Neuerungen in ihre Werkzeuge zu integrieren.

C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++

Page 3: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

67

C++11 . net-sprachen

www.windowsdeveloper.de9.2012

nullptrZeiger sind in C/C++ ein Sprachkonstrukt der ersten Stunde. Sie verweisen auf andere Variablen, speichern deren Adresse oder eben nicht. Bislang hat der C++-Programmierer eine explizite Konstante für einen Zei-ger, der auf nichts zeigt, vergeblich gesucht. nullptr löst nun den per Konvention getroffenen Wert 0 oder den in vielen Compilern verwendeten #de� ne NULL 0 ab. Neben einer besseren Lesbarkeit werden dadurch auch einige Fehlersituationen umgangen, die nach der bisherigen Konvention durchaus Probleme gemacht haben. So ist nullptr in sämtliche Zeigerdatentypen implizit konvertierbar, nicht aber in integrale Daten-typen mit Ausnahme von bool:

char *pChar = nullptr; // OKint * pInt = nullptr; // OKint val = nullptr; // error

Interessant wird dies in folgender Situation:

void f(char *);void f (int);f(nullptr);

autoC++ ist eine streng typgebundene Sprache. Daher mussten bislang Variablen auch unter Angabe des gewünschten Typs vereinbart werden. Das Problem dabei: Seit der Einfüh-rung von Templates ist der Rückgabetyp einer Funktion nicht immer so einfach zu erken-nen, trotz Mechanis-men wie IntelliSense. Die meisten von uns werden die Situation kennen, dass ein Aufruf der ge-wünschten Funktion durch einen Compilerfehler quit-tiert wird. Dieser besagt dann in etwa, dass der Typ <hier<folgen<nun, zweihundertsiebenundachzig>, <Zei chen, oder mehr>>> nicht in int konvertiert wer-den kann. Und zumindest mir gelingt es trotz höchster Konzentration meist auf Anhieb nur <ich, gebe, <nun, 287>, Zeichen, wieder>, so<wie, ich, Sie<gelesen>, habe> einzutippen. Es folgen dann Momente, in denen mich die Beharrlichkeit eines Compilers in leichte Er-regung versetzen kann. Mit auto wird dieses Problem endlich gelöst:

auto result = ThisFunctionReturnsANestedTemplate();

auto kann für alle Variablen verwendet werden, die di-rekt bei ihrer De� nition initialisiert werden, und wird vom Compiler automatisch durch den Typ des Initia-lizer ersetzt, bei Funktionsaufruf durch den Datentyp

des Rückgabewerts – ein einfaches, aber sehr nützliches Sprachmerkmal. Die bisherige Bedeutung von auto ist nun deprecated, d. h. sollte nicht mehr genutzt werden und wird wohl irgendwann komplett entfallen.

To Collect or not CollectDas Thema Garbage Collector beschäftigt die C++-Community immer wieder. Bei zahlreichen Veran-staltungen werden wir als Berater gefragt, wann denn endlich ein Garbage Collector in C++ Einzug halten wird. Die einfache Antwort: Wohl niemals, er wird ei-gentlich nicht benötigt. Ursache für die Diskussionen um das Thema Garbage Collector sind zum einen die C++-verwandten Programmiersprachen Java und C#. Sie wurden mit viel Wirbel um eben jenen eingeführt, und zum anderen liefert natürlich auch das eigentli-che Problem der Memory Leaks entsprechend Zünd-stoff. Diese waren der eigentliche Motivationsgrund für Garbage Collectors. Doch die Räder drehen sich weiter. Zwischenzeitlich hat sich vieles bezüglich der Vermeidung von Memory Leaks getan. Grenzt man das Problem genauer ein, so stellt man folgende Punk-te fest:

•Value Types vs. Reference Types: C++ als Pro-grammiersprache arbeitet per Default mit Value Types. Auch Klassen de� nieren Value Types. Alles, was in C++ als integraler Datentyp angelegt wird, wird bei Verlassen des Gültigkeitsbereichs automa-tisch bereinigt. Somit sind herkömmliche integrale

Member-Variablen und Stack-Variablen nicht das Problem in C++. Garbage-Collected-Sprachen dagegen legen Instanzen von Klassen immer auf dem Heap an. Value Types gibt

es, sie sind aber recht dünn gesät.•Destruktoren werden in C++ immer deterministisch

aufgerufen, dies auch beim Verlassen des Gültig-keitsbereiches der entsprechenden Variablen. In Garbage-Collected-Sprachen ist dies nicht der Fall. In C# z. B. wird der Finalizer erst dann aufgerufen, wenn der Garbage Collector das entsprechende Objekt aufräumt.

Somit machen in C++ eigentlich nur Objekte bzw. Speicherbereiche Probleme, die explizit per new auf dem Heap allokiert und über einen Zeiger verwaltet werden. Geht dieser out of Scope, bevor delete auf-gerufen wurde, so entsteht das gefürchtete Memory Leak. Die Kombination der beiden eben gerade aufge-führten Sachverhalte liefert jedoch bereits die Lösung des Problems. Smart Pointer kapseln den Zeiger in ei-nem kleinen Hüllobjekt, das im Destrukor delete auf-ruft. Dies geschieht genau dann, wenn das Hüllobjekt seinen Gültigkeitsbereich verlässt und ist somit abso-

Was lange währt, wird endlich wahr

Der Garbage Collector beschäftigt die C++-

Community immer wieder.

Page 4: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

68

.net-sprachen . C++11

9.2012

lut deterministisch. Ergo: Wer braucht schon einen Garbage Collector? Umgekehrt betrachtet bringt auch ein Garbage Collector Probleme mit sich: Verwaltet ein Objekt eine Unmanaged Resource, so genügt es oftmals nicht, diese im Destruktor/Finalizer freizuge-ben. Dieser wird erst zeitverzögert durch den Garbage Collector und damit nicht deterministisch aufgerufen. Handelt es sich bei dieser Unmanged Resource um eine exklusiv geöffnete Datei, steht diese für andere eine unvorhersehbare Zeit nicht zur Verfügung. Und somit haben wir ein Resource Leak – umgekehrtes Problem, aber vergleichbarer Effekt! Die Schöpfer der Garbage-Collected-Programmiersprachen haben hierfür das Dispose Pattern nachgereicht. Es sieht eine Methode vor (C#: Dispose(), Java: dispose()), die explizit auf-gerufen werden muss und die Unmanaged Resource freigibt, bevor das Objekt seinen Gültigkeitsbereich verlässt. Um diesen Aufruf sicherzustellen, muss sehr häu�g try/catch/�nally bemüht werden. Zur Verein-fachung wurde in C# hierfür extra das Schlüsselwort using eingeführt. Verglichen damit sind Smart Pointer in C++ auch nicht komplizierter.

Smart PointersSeit der Einführung von Templates lassen sich Smart Pointers sehr einfach realisieren. Das Template auto_ptr wird von den meisten C++-Compilern seit Jahren unter-stützt. Bibliotheken wie Boost haben dieses Pattern in den letzten Jahren nennenswert erweitert. Die entspre-chenden Smart-Pointer-Templates haben in C++ STL nun eine Normierung erfahren. unique_ptr löst dabei den bereits angesprochenen auto_ptr (deprecated) ab und stellt den einfachsten Smart Pointer dar:

{ unique_ptr<sometype> p = new sometype; p->func();} // dtor of p deletes "new sometype"

Sobald jedoch mehrere Bezüge auf ein Objekt verwal-tet werden müssen, genügt das einfache Modell von unique_ptr nicht mehr. Das Objekt auf dem Heap darf erst freigegeben werden, nachdem der letzte Be-zug seinen Gültigkeitsbereich verlassen hat. Hier hilft shared_ptr (Listing 1).

shared_ptr arbeitet über einen Referenzzähler, der bei Zuweisungen inkrementiert und durch den De-

struktor dekrementiert wird. make_shared sorgt da-für, dass der Referenzzähler beim Anlegen des Objekts sicher arbeitet und kapselt den Aufruf von new. Ein Problem bei Reference Counting stellen zyklische Re-ferenzen dar. Zwei sich gegenseitig referenzierende Objekte halten den jeweiligen Zähler auf 1, die Ob-jekte werden somit nicht mehr freigegeben. Auch dies ist berücksichtigt, die STL bietet hierfür das Template weak_ptr an. Neben den eigentlichen Smart Pointers sorgt die STL mit einer ganzen Menge an überlade-nen Operatoren dafür, dass der Umgang mit Smart Pointers einfach und recht fehlerresistent ist. Richtig angewendet wird damit der Operator delete in eige-nen Anwendungen nahezu über�üssig. Es genügt, sich einmalig bei der Vereinbarung des Zeigers Gedanken über den Lebenszyklus des dahinterstehenden Objekts zu machen und den richtigen Smart Pointer einzuset-zen, den Rest regelt dieser selbst. Wer weiterhin hart-näckig auf den Einsatz von delete besteht, kann dies natürlich tun. Er muss sich dann aber bei Verlassen des Gültigkeitsbereichs eines Zeigers Gedanken ma-chen, was mit dem dahinter stehenden Objekt gesche-hen soll, und das wird auf deutlich mehr Stellen im Code hinauslaufen.

LambdasCallbacks sind ein uraltes Konzept und stellen ein we-sentliches Leistungsmerkmal dar, das moderne Soft-warearchitekturen erst möglich macht. Layer-basierte Software setzt voraus, dass die Abhängigkeit zwischen den Schichten nur in eine Richtung geht: von oben nach unten. Komponentenbasierte oder serviceorien-tierte Modelle nutzen andere Begriffe, meinen aber das Gleiche: Eine Anwendung nutzt eine Komponen-te oder einen Service, nicht umgekehrt. Ohne einen Callback wäre damit auch die Richtung der Funkti-onsaufrufe eine Einbahnstraße, damit sind heutige An-wendungen nicht zu realisieren. C und C++ bieten zur Realisierung eines Callback klassische herkömmliche Funktionszeiger, Zeiger auf Elementfunktionen, an. In C++ steht natürlich auch die Nutzung von Schnittstel-len als Option offen. Gemeinsam haben alle Ansätze, dass die Signatur der Funktion von der Komponente de�niert und bereits genutzt werden kann, die Imple-mentierung aber erst später durch die Anwendung oder eine höhere Schicht nachgereicht wird. Nur auf diese Weise können Komponenten kompiliert werden, ohne die konkreten Nutzer benennen zu müssen, das Henne-Ei-Problem ist dadurch gelöst.

Seitdem dieses Modell verinnerlicht ist, haben im-mer mehr Bibliotheken ausführlich davon Gebrauch gemacht. Die Folge ist, dass viele Anwendungen zwi-schenzeitlich aus mehr Callbacks bestehen als aus eigentlichen Funktionen. Und da alle bisherigen An-sätze Funktionen zur Implementierung des Callbacks voraussetzen, wird natürlich auch die Unterscheidung zwischen Funktion und Callback – und damit die Auf-rufrichtung – recht schwierig. Ansätze mit On Irgend-

Abb. 1: Lambda

422_STAMMDATEN_anz_rz.indd 1 20.06.12 15:28

Page 5: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

C++11 . net-sprachen

was kennt jeder, doch eine Namenskonvention ist eben nur eine Namenskonvention. Lambdas liefern hier eine Lösung, denn sie erlauben die De�nition des Callbacks an jeder beliebigen Stelle im Code, insbesondere eben auch innerhalb einer anderen Funktion. Und damit rutscht die Implementierung vom Global oder Class Scope in den Function Scope. Sie wird ganz exakt zu-geordnet und weggekapselt. Ein Lambda kann somit auch als lokale Funktion bezeichnet werden, ist syn-taktisch jedoch noch deutlich mächtiger. Mit einem Lambda wird eine lokale Funktion vereinbart. Abbil-dung 1 zeigt die Bestandteile eines Lambdas:

1. Die Parameterliste vereinbart die Lambda-Para-meter. Sie werden später beim Aufruf wie bei her-kömmlichen Funktionen angegeben.

2. Der Rückgabetyp steht an einer anderen Stelle, ansonsten gelten aber die altbekannten Regeln. Aus-nahme: Wird er nicht explizit angegeben, so richtet er sich nach dem return im Rumpf.

3. Der Funktionsruf wird wieder identisch wie bei einer Funktion vereinbart.

4. throw gibt an, ob Exceptions ausgelöst werden, auch hier gelten die Regeln wie bei Funktionen.

5. Über die Capture Clause wird geregelt, wie mit loka-len Variablen der umschließenden Funktion umge-gangen werden soll.

6. mutable erlaubt eine feinere Regulierung des Verhal-tens der in der Capture Clause angegebenen Varia-blen.

Die Capture Clause ist es, die das Besondere am Lamb-da darstellt und einer genaueren Betrachtung bedarf. Einige Beispiele werden in Listing 2 dargestellt. Die beiden Lambdas lambda1 und lambda2 zeigen jeweils die Vereinbarung und die Nutzung, sprich den Aufruf, einmal ohne und einmal mit Parameter. Dabei wird deutlich, dass das Lambda selbst einen Wert darstellt, der einer Variablen zugewiesen werden kann. Dank auto machen wir uns in der Regel keine weiteren Ge-danken mehr über den exakten Typ der Variablen, es

422_STAMMDATEN_anz_rz.indd 1 20.06.12 15:28

Listing 1

{ shared_ptr<sometype> sp1;

{ shared_ptr< sometype > sp2; sp2 = make_shared< sometype>(); sp1 = sp2; } // sp2 goes out of scope} // sp1 goes out of scope

Page 6: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

70

.net-sprachen . C++11

9.2012

steckt tatsächlich aber ein Template dahinter, das die unterschiedlichen Ausprägungen möglicher Lambdas typsicher macht – man denke alleine an die Anzahl der Lambda-Parameter.

Das in Listing 2 dargestellte lambda3 zeigt die Ver-wendung der Capture Clause. Im Rumpf des Lambdas wird auf die Variable strMessage zugegriffen, die we-der lokal noch als formaler Parameter de�niert wur-de. strMessage kommt aus dem Gültigkeitsbereich der umgebenden Funktion, im konkreten Fall ist dies De-moLambda. Somit erlaubt es die Capture Clause, gezielt den Gültigkeitsbereich des Lambdarumpfes um einzel-ne Variablen zu erweitern. Im Folgenden sehen Sie eine Übersicht der Capture Clause:

•[] – Bleibt das Capture Clause leer, so können keine Va-riablen aus dem umgebenden Scope genutzt werden.

•[=] – Es werden alle Variablen des umgebenden Gül-tigkeitsbereiches im Lambda gültig. Sie werden bei Aufruf implizit als weitere Parameter by value über-geben.

•[&] – Es werden alle Variablen des umgebenden Gültigkeitsbereichs im Lambda gültig, die Übergabe erfolgt nun aber by reference.

•[strMessage] – Es wird ausschließlich die angegebene Variable strMessage by value übergeben.

•[&strMessage] – Es wird ausschließlich die angegebe-ne Variable strMessage by reference übergeben.

Die aufgeführten Capture Clauses lassen sich weiter kombinieren. Sollen mehrere, aber nicht alle Varia-blen gezielt weitergereicht werden, so werden diese einfach innerhalb der eckigen Klammern kommage-trennt aufgelistet. Auch Kombinationen wie [=, &str-Message] sind möglich – hier werden alle Variablen by value zugänglich, strMessage aber wird by reference übergeben.

Warum aber werden die über die Capture Clause fest-gelegten Variablen nicht einfach als weitere Variablen in der Parameterliste hinzugefügt? Nach ein wenig Überle-gung kann die Antwort selbst erkannt werden: Es geht um den Zeitpunkt der Parameterübergabe. Oder anders ausgedrückt: Wer legt die aktuellen Parameter fest? Bei der herkömmlichen Parameterliste ist dies der Rück-rufer, bei der Capture Clause ist es der Rückgerufene. Die Werte der Capture-Clause-Variablen werden zum Zeitpunkt der De�nition des Lambdas gebunden, bei der herkömmlichen Parameterliste geschieht dies zum Zeitpunkt des Rückrufs.

Neue Containerklassen in der STLDass es in der STL auch eine Reihe an Containerklas-sen gibt, versteht sich von selbst. Neu ist mit C++11 nun aber die Nutzung der eben vorgestellten Lambda-syntax. Die STL macht hier ausgiebig Gebrauch da-von. Listing 3 zeigt ein Beispiel, das die Verwendung des STL templates vector zeigt. Besonders dabei ist die Verwendung der for_each loop. Diese iteriert über alle Elemente des Vektors und führt für jedes das angege-bene Lambda aus. So kann recht einfach, wie mit print, ein Lambda de�niert werden, das dann in mehreren for_each-Schleifen zum Einsatz kommt, eine lokale

Listing 2: Beispiele zu Lambdas

void DemoLambda(){ auto lambda1 = [] () { cout << "lambda1" << endl; }; lambda1();

string strMessage = "hello again"; // try 'string s', 'string &s' auto lambda2 = [] (string s) { cout << "lambda2: " << s << endl; }; lambda2(strMessage); strMessage = "good bye my dear"; lambda2(strMessage);

strMessage = "hello again"; // try [], [=], [&], [strMessage], [&strMessage] auto lambda3 = [&strMessage] () { cout << "lambda3: " << strMessage << endl; }; lambda3(); strMessage = "good bye my dear"; lambda3();

int a=1; // try '[=]', '[=] mutable', [&] auto lambda4 = [=] () mutable { cout << "lambda4: " << a++ << endl; }; lambda4(); a = 56; lambda4(); cout << "a: " << a << endl;

auto lambda5 = [] (int param) -> int { cout << "lambda5: " << param << endl; return 2*param; }; a = lambda5(a); a = lambda5(a); cout << "a: " << a << endl;}

Page 7: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern
Page 8: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

72

.net-sprachen . C++11

9.2012

Funktion eben. Der Aufruf des Lambdas geschieht da-bei innerhalb von for_each, d. h. innerhalb der STL. Denn: for_each ist kein Schlüsselwort, sondern eine Template-Funktion, die von der STL gestellt wird.

Listing 3 zeigt auch die Verwendung weiterer STL Templates: sort, transform und copy_if. Alle verwen-den als Parameter ein Lambda. Mal ist es eine Ver-

gleichsfunktion für die Sortierung, mal ein Konverter, der z. B. aus einem Vektor mit Strukturen ein kon-kretes Element jeder Strukturinstanz in einen neuen Vektor mit Integer-Werten wandelt, oder eine Prüf-funktion, die dafür sorgt, dass nur einzelne Elemente eines Vektors in einen anderen übernommen werden. Schöne neue Welt der Lambdas!

Recht interessant ist auch die Tatsache, dass die meis-ten Compilerhersteller bereits beginnen, diese neuen Leistungsmerkmale mit ihren teilweise proprietären Bi-bliotheken zu verheiraten. Microsoft zum Beispiel sorgt in Visual Studio 2012 dafür, dass die Containerklassen der STL sehr smooth in Containerklassen der WinRT [1] konvertieren und umgekehrt.

rvalue referencesIn C++99 gibt es keine Möglichkeit, beim Überladen von Funktionen mit einem Referenzparameter zu unter-scheiden, ob dieser beim Aufruf mit einem rvalue oder einem lvalue belegt wurde:

int a=0;void f(int &i); // lvalue referencef(a); // OK, a ist lvaluef(5); // error, 5 is rvalue

Um den resultierenden Compilerfehler zu umgehen, be-hilft sich der C++99-Programmierer mit dem Überladen der Funktion f():

void f(int &i); // lvalue referencevoid f(const int &i); // const lvalue reference

f(5); // calls void f(const int &i)

Doch dies ist nicht genau das, was gewünscht ist, denn nun wird der Parameter i innerhalb der Funktion f const und kann damit nicht mehr modi�ziert werden. C++11 führt zur vollwertigen Unterscheidung von lva-lue und rvalue reference eine neue Syntax ein:

void f(int &i); // lvalue referencevoid f(const int &i); // const lvalue referencevoid f(int &&i); // rvalue reference

f(5); // calls void f(int &&i)

copy-Semantikrvalue references erscheinen auf den ersten Eindruck recht „theoretisch“. Was ist so toll daran? Dazu folgen-der Codeauszug:

mystring f(){ mystring result("we will return this"); return result;}

Listing 3: Lambdas und for_each

void DemoSort()

{

vector<int> v;

for(int i=0; i<10; i++)

{

int val = rand()%100+1;

v.push_back(val);

}

auto print = [] (int &val)

{ cout << val << endl; };

for_each(begin(v), end(v), print);

cout << endl;

auto comp = [] (int lhs, int rhs)

{ return lhs<rhs; };

sort(begin(v), end(v), comp);

for_each(begin(v), end(v), print);

cout << endl;

auto lb = lower_bound(begin(v), end(v), 50);

auto ub = upper_bound(lb, end(v), 70);

for_each(lb, ub, print);

cout << endl;

vector<int> result;

transform(begin(v), end(v),

inserter(result, result.end()),

[] (int val) -> int

{ return (val>=50 && val <=70) ? val : 0; } );

for_each(begin(result), end(result), print);

cout << endl;

result.clear();

copy_if(begin(v), end(v),

inserter(result, result.end()),

[] (int val) -> bool

{ return (val>=50 && val <=70); } );

for_each(begin(result), end(result), print);

cout << endl;

}

Page 9: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

73

C++11 . net-sprachen

www.windowsdeveloper.de9.2012

Die mit (2) und (3) gekennzeichneten Aufrufe sind un-nötig, denn eigentlich genügt es, einmalig den Spei-cher für "content from g" freizugeben und den neuen Speicher für "content from f" anzulegen. Die Copy-Semantik führt zu einem Overhead mit Faktor 3.

move-SemantikDie Lösung des Copy-Problems kommt mit der C++11-move-Semantik. Diese wiederum macht auch anschau-lich, welchen Nutzen die Unterscheidung zwischen lvalue

Was ist hier das Problem? Beim dem einen oder ande-ren C++-Programmierer läuten hier bereits die Alarm-glocken, denn er hat dieses Problem selbst schon einmal durchleben müssen. Hier noch eine weitere, analoge Situation:

void f(mystring s){}

Problematisch wird die Sache, wenn unsere Klasse my-string den Inhalt dynamisch auf dem Heap ablegt, in einem herkömmlichen Zeiger speichert und im Destruk-tor den Speicher bereinigt:

class mystring{ // ... skipped char *content; ~mystring() { delete content; }};

C++ arbeitet standardmäßig mit Value Types, auch ein char * ist einer. Und Value Types werden standardmä-ßig binär kopiert. Somit entstehen in beiden dargestell-ten By-Value-Szenarien zwei Zeiger auf den gleichen Heap-Speicher. Allgemeiner ausgedrückt, hängt dieses Problem ständig wie ein Damoklesschwert über uns C++-Programmierern. Sobald eine Klasse einen Destruktor besitzt, sollten wir uns zumindest Gedanken machen. Die Lösung des Problems ist seit Langem in C++ de�niert. Es muss ein Copy-Konstruktor de�niert oder der Standard-Copy-Konstruktor zumindest deaktiviert werden:

class mystring{ // ... skipped mystring(const mystring& init);};

Für das Deaktivieren genügt es, den Copy-Konst-ruktor private zu vereinbaren, ansonsten bedarf es natürlich einer Implementierung, die den hinter init stehenden Inhalt in das neue Objekt kopiert. Analog gilt das Ganze übrigens auch für die Zuweisung, also operator= (Listing 4).Damit ist das Problem an und für sich gelöst, jedoch ist dies nicht immer unbedingt sonderlich ef�zient. Hinsichtlich Heap entsteht fol-gende Aufrufsequenz:

•s1.content = new - "content from g" (1)•result.content = new - "content from f" (2)•rhs.content = new - "content from f" (3)•delete result.content - "content from f" (2)•delete s1.content - "content from g" (1)•s1.content = new - "content from f" (4)•delete rhs.content - "content from f" (3)•delete s1.content - "content from f" (4)

Listing 4

class mystring

{

// ... skipped

char *content;

~mystring() { delete content; }

mystring(const char *init);

mystring(const mystring& init);

mystring& opertor=(const mystring& rhs);

};

mystring f()

{

my string result("content from f");

return result;

}

void g()

{

mystring s1("content from g");

s1 = f();

}

Listing 5

class mystring

{

// ... skipped

char *content;

~mystring() { delete content; }

mystring(const char *init);

mystring(const mystring & init);

mystring(mystring && init);

mystring& opertor=(const mystring& rhs);

mystring& opertor=(mystring&& rhs);

};

mystring::mystring(string&&init) :

data(move(init.content)

{

init.content = nullptr;

}

Page 10: 9.2012 Windows Phone Phone · 66.net-sprachen. C++11 9.2012 von Thomas Trotzki und Christian Binder C/C++ hat eine lange Geschichte und noch immer eine sehr große Zahl an Anhängern

74

.net-sprachen . C++11

9.2012

und rvalue reference beim Überladen von Funktionen bringen kann. Tatsächlich ist es nämlich so, dass gerade für rvalues das Erzeugen einer Kopie unnötig ist, hier ge-nügt es, den Inhalt zu verschieben (Listing 5). Besonders ist hier noch die Verwendung von move(init.content) zu erwähnen. De�niert der an move übergebene Parameter selbst einen move-Konstruktor, so wird dieser aufgeru-fen, ansonsten wird eine bitweise Kopie erstellt.

Neuerungen bei der VererbungAuch bei der Vererbung gibt es einige kleine Ände-rungen, die C++ ein Stück besser machen. Bekannt sind die entsprechenden Konzepte von Java und C#. Mit dem neuen Schlüs-selwort override beim Überschreiben von vir-tuellen Funktionen in einer abgeleiteten Klasse wird der Compiler an-gewiesen abzuprüfen, dass eine entsprechende virtuelle Funktion in einer Basisklasse auch tatsächlich existiert und ein Fehlen mit einem Compilerfehler zu quittieren. Damit wird ein versehentliches Überladen anstelle des gewünschten Überschreibens abgefangen. Besonders hilfreich ist override damit nicht nur beim erstmaligen Implementieren der abgeleiteten Klasse, sondern auch beim P�egen der Signaturen der virtuellen Funktionen in der Basisklasse (Listing 6). Ebenso erlaubt es C++11 ein Überschreiben einer virtuellen Funktion in einer weiteren Ableitung zu unterbinden. Hierfür wird das Schlüsselwort �nal analog zu override verwendet:

class derived : public base{public: virtual void f(int) final;};

Und zu guter Letzt kann auch eine weitere Ableitung komplett unterbunden werden, hierfür wird �nal ans Ende einer Klassenvereinbarung gestellt:

class derived final : public base { };

FazitMit C++11 wird C++ erneut ein Stück moderner und beinhaltet nun alle Leistungsmerkmale, die bis-lang bei einem Vergleich mit Java und C# eventuell schmerzlich vermisst wurden. Durch sinnvollen Ein-satz der STL werden unbeabsichtigte Fehler deutlich unwahrscheinlicher und in C++ erstellte Anwendun-gen robuster. Auf einen Garbage Collector verzichten zu müssen, ist keine Schande, im Gegenteil: In keiner anderen Sprache kann so gezielt jederzeit entschieden werden, ob gerade Abstraktion oder Laufzeit eine höhere Bedeutung haben soll wie in C++. Damit ist und bleibt C++ die mächtigste Programmiersprache

schlechthin. Modernes C++11 hat mit auto, lamdba, sharedPtr und Co. im Kontext von Produktivität einen deutlichen Schritt nach vorne gemacht. Es lohnt sich, diese Mechanis-

men zu nutzen. Auf die nächsten 30 Jahre!Doch es wird noch weiter gehen. Auf der ADC ++

Anfang Mai in Ohlstadt haben Michael Wong (IBM, Representative to the C++ Committee ), Steve Teixei-ra und Boris Jabes (Microsoft-C++-Team) Einblick in die aktuellen Themen des C++ Committee gegeben. Als Nächstes stehen in dieser Artikelserie Themen wie Multitasking und weitere große Bibliotheken zur Nor-mierung an.

Thomas Trotzki ist ALM Consultant bei der artiso AG nahe Ulm und Microsoft-C++-Pro� der ersten Stunde. Mit Microsoft C++ und den MFC beschäftigt er sich intensiv seit den ersten Betaversionen zu Microsoft C/C++ 7.0, also bereits vor der Geburtsstunde von Visual C++ und Visual Studio. Technologisch ist er neben C++ und

den MFC auch mit COM/DCOM und der gesamten „Managed Welt“ vertraut und hat umfangreiche Expertise im Application Lifecycle Management.

Christian Binder arbeitet als ALM Architect in der Developer Plat-form & Strategy Group bei Microsoft Deutschland. Er arbeitet seit 1999 bei Microsoft, u. a. als Escalation Engineer, dann Platform Strategy Manager und kann so auf umfangreiche Erfahrungen im Bereich Application Development zurückgreifen. Auch war er im

Product Development von Microsoft in Redmond tätig, was ihn 2005 zum Thema Application Lifcycle Management gebracht hat.

Links und Literatur

[1] http://msdn.microsoft.com/en-us/library/windows/apps/hh700103(v=vs.110).aspx

Listing 6class base{public: virtual void f(int);};

class derived : public base{public: virtual void f(int) override;};

Mit C++11 wird C++ ein Stück moderner und hält dem Ver-gleich mit Java und C# stand.

14. – 17. 10.2012Rheingoldhalle MainzExpo 16. – 17. 10.2012

www.webtechcon.de

Exklusiv bis 16. August

Frühbucherpreise

+ Gratis-Notebook

= 650 Euro sparen!

webtechcon | #wtc12

webtechcon

Platin-Partner: Gold-Partner: Silber-Partner: Bronze-Partner:

VeranstalterPräsentiert von

Media-Partner