Open Source im professionellen Einsatz

Einfacheres Arbeiten mit der Standard Library

Viele der neuen Features sind mit einem hochaktuellen GCC 4.5 schon lauffähig (siehe Kasten "Compilerunterstützung"). Zum Übersetzen von Listing 3 ist lediglich die Range-basierte For-Schleife »for (auto x : myInt)« in Zeile 8 auszukommentieren. Demgegenüber steht in Zeile 9 ein klassischer C++-Ausdruck, um über einen Container zu iterieren. Verpackt man den Codeschnipsel aus Listing 3 in ein Programm, kompiliert es und führt es aus, erscheint die erwartete Ausgabe (Abbildung 3). Die neuen »{}«-Initialiser räumen mit der uneinheitlichen Initialisierung von Objekten auf und lassen sich für alle Initialisierungen verwenden. Listing 3 zeigt, wie leicht das direkte Initialisieren eines Algorithmus (Zeile 25) oder eines Map-Containers (Zeile 27) durch ein Aggregat von der Hand geht.

Auch den Vektor in Listing 2 initialisiert ein Aggregat:

std::vector <int> vec1={1,2,3,4,5,6,7,8,9};

So weichen neun Methodenaufrufe einer Aggregatzuweisung. Gerade der C++-Novize wird dieses Feature dankbar annehmen, kann er doch jetzt intuitiv seine Objekte initialisieren. Ein paar weitere Beispiele (Listing 4) zeigen, dass »{}«-Initialiser natürlich auch im Kleinen anwendbar sind.

Compilerunterstützung

Im Stdcxx-Wiki [2] ist dargestellt, wie weit die bekannten Compiler den C++0x-Standard umsetzen. Diese Unterstützung bezieht sich allerdings nur auf die Kernsprache. Hier hat der GCC deutlich die Nase vorn. Dank der TR1-Bibliotheken des GCC 4.5 stehen darüber hinaus fast alle Bibliothekserweiterungen des neuen Standards zur Verfügung. Lediglich für Regular-Expression- und Threading-Bibliotheken sind Include-Dateien und Bibliotheken aus Boost [3] erforderlich.

Das ist durchaus legitim, dienen diese doch als Grundlage für die aktuelle Bibliothekserweiterung TR1. Mit ein bisschen Bastelarbeit ist es daher möglich, einen Großteil des neuen Standards C++0x im praktischen Einsatz kennenzulernen.

Listing 3: Rund und die Standard
Library

01 std::vector <int> myInt(10);
02 std::cout  << "vector of 10 times 0: ";
03 for (auto itr = myInt.begin(); itr != myInt.end(); ++itr){
04   std::cout << *itr << " ";
05 }
06 std::cout << "nn";
07 
08 // for (auto itr : myInt) { std::cout <<  *itr << " ";}
09 // for (std::vector<int>::const_iterator itr= intInt.begin(); itr != myInt.end(); ++itr){ ... }
10 
11 std::iota(myInt.begin(), myInt.end(),1);
12 std::cout << "Increment each value by 1: ";
13 for (auto itr = myInt.begin(); itr != myInt.end(); ++itr){
14   std::cout << *itr << " ";
15 }
16 std::cout << "nn";
17 
18 std::sort(myInt.begin(),myInt.end(),[](int a, int b){ return a > b;} );
19 std::cout <<  "Sort the vector of natural numbers: ";
20 for (auto itr = myInt.begin(); itr != myInt.end(); ++itr){
21   std::cout << *itr << " ";
22 }
23 std::cout  << "nn";
24 
25 std::cout<< "std::min({1,2,4,0,1,-5,2}): " << std::min({1,2,4,0,1,-5,2}) << "nn";
26 
27 std::map<std::string,std::string> phonebook =
28   {{"Bjarne","+1 (012) 555-1212"},
29    {"Herb", "+1 (345) 555-3434"},
30    {"Alexandrei","+1 (678) 555-5656"}};
31 std::cout << "Get each telephone number:  n";
32 for (auto itr = phonebook.begin(); itr!= phonebook.end(); ++itr){
33   std::cout << itr->first << ": " << itr->second << "n;
34 }

Listing 4:
Initialiser-Listen

01 Base x = Base{1,2};
02 Base* p = new Base{1,2};
03 
04 struct Derived : Base {
05   Derived(int x, int y) :Base{x,y} {};
06 };
07 
08 func({a});        // function invocation
09 return {a};       // function return value

Neue Algorithmen und Lambda-Funktionen

Ist der Container in Listing 3 initialisiert, kann ihn der Programmierer modifizieren. Dazu bietet C++0x neue Algorithmen an, »std::iota« in Zeile 11 etwa inkrementiert die Elemente des Vektors sukzessive um 1. Aber es gibt noch viele mehr [5]: »std::min« lässt sich entsprechend zum Algorithmus »std::sort« (Zeile 18) mit einer Funktion parametrisieren. Klassisches C++ würde dazu eine Funktion oder ein Funktionsobjekt [6] verwenden. Mit C++0x schreibt sich das viel kompakter, denn der neue Standard kennt Lambda-Funktionen, auch anonyme Funktionen genannt, sie sind eine Anleihe bei der funktionalen Programmierung. Damit lässt sich die Vergleichsfunktion genau an der Stelle definieren, an der sie benötigt wird.

Der folgende Ausdruck gibt 0 als Ergebnis zurück, denn es wird der minimale Wert über allen absoluten Werten gesucht:

std::min({1,2,4,0,1,-5,2},[](int a,int b){ U return abs(a) < abs(b); })

»,[](int a,int b){ return abs(a) < abs(b); }« ist die Lambda-Funktion. Die Struktur von Lambda-Funktionen in C++0x:

  • »[]«: Bindung an die Variablen des lokalen Scope.
    Dabei bedeutet »[]« keine Bindung, »[=]«
    die Werte werden kopiert, »[&]« referenziert die
    Werte des lokalen Scope.
  • »()«: Die Argumente des Funktionskörpers
    (optional).
  • »{}«: Der Funktionskörper.

Alle Details rund um Lambda-Funktionen in C++0x lassen sich bei Danny Kalev [7] ausführlich nachlesen.

Es wird noch mächtiger: Einerseits sind Lambda-Ausdrücke First Class Functions [8] und lassen sich insbesondere wie Daten behandeln. Andererseits ist mit »auto« (der letzte weiße Fleck aus Listing 3) automatisch der Typ ableitbar. Beide Komponenten ermöglichen - miteinander verknüpft - den einfachen Umgang mit Lambda-Funktionen.

Listing 5: »auto«
und Lambda-Funktionen verknüpft

01 auto myAdd= [](int a, int b){return a + b;};
02 std::cout << "myAdd(1,2): " << myAdd(1,2) << std::endl;

Listing 6:
»decltype«

01 std::vector <int > myVecInt={1};
02 std::vector <double> myDoubleInt={1.1};
03 decltype(myVecInt[0]*myDoubleInt[0]) myDouble = 2.1;

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook