Open Source im professionellen Einsatz
Linux-Magazin 02/2014

Modernes C++ in der Praxis – Folge 14

Neue Ausdruckskraft

In C++11 lässt sich manches prägnanter formulieren als in klassischem C++. Dieser Artikel zeigt, wie die neue Range-basierte For-Schleife und die automatische Typableitung dabei helfen.

634

Einfache Dinge sollten einfach, schwierige Dinge möglich sein. Was wie die oberste Maxime jeder Programmiersprache klingt, war in C++ lange keine Selbstverständlichkeit. Dank der Range-basierten For-Schleife und der automatischen Typableitung in C++11 gehört das aber der Vergangenheit an. Standardaufgaben wie das Arbeiten mit einem Container gehen mit dem starken Duo deutlich einfacher von der Hand.

Die harte Tour

In klassischem C++11 gestalten sich das Füllen eines Containers und das Ausgeben seiner Elemente sehr wortreich. Listing 1 exerziert dies für den sequenziellen »std::vector« und den assoziativen Container »std::unordered_map« durch. Details zu den assoziativen Containern lassen sich im vorigen Artikel [1] dieser Serie nachlesen.

Die Arbeit beginnt mit dem Füllen des Containers. Dazu muss der Programmierer beim »std::vector« jedes einzelne Element mit »push_back()« (Zeilen 12 bis 16) auf den Vektor schieben. Zwar besorgt diese Operation den notwendigen Speicher für die neuen Elemente, sie ist aber unangenehm wortreich.

Listing 1

std::vector und std::unordered_map ausgeben

01 #include <iostream>
02 #include <string>
03 #include <unordered_map>
04 #include <utility>
05 #include <vector>
06
07 int main(){
08
09   std::cout << std::endl;
10
11   std::vector<int> myVec;
12   myVec.push_back(1);
13   myVec.push_back(2);
14   myVec.push_back(3);
15   myVec.push_back(4);
16   myVec.push_back(5);
17
18   std::vector<int>::const_iterator vecIt;
19   std::vector<int>::const_iterator vecItEnd= myVec.end();
20
21   for (vecIt= myVec.begin(); vecIt != vecItEnd; ++vecIt){
22     std::cout << *vecIt << " ";
23   }
24
25   std::cout << "\n\n";
26
27   std::unordered_map<std::string,int> myUnordMap;
28   myUnordMap.insert(std::pair<std::string,int>("Dijkstra",1972));
29   myUnordMap.insert(std::make_pair("Scott",1976));
30   myUnordMap["Ritchie"]= 1983;
31
32   std::unordered_map<std::string,int>::const_iterator unordIt;
33   std::unordered_map<std::string,int>::const_iterator unordEnd= myUnordMap.end();
34
35   for (unordIt= myUnordMap.begin(); unordIt != unordEnd; ++unordIt){
36       std::cout << unordIt->first << ": " << unordIt->second << std::endl;
37   }
38
39   std::cout << std::endl;
40
41 }

Container füllen

Der neue Container »std::unordered_map« ist mit der klassischen Syntax ähnlich kompliziert zu füllen. Für jedes Schlüssel-Wert-Paar ist eine eigene Anweisung notwendig (Zeilen 28 bis 30). Sind die Container gefüllt, geben die Zeilen 21 und 35 ihren Inhalt aus. Auch das gestaltet sich sehr umständlich.

Bei »std::vector« , dem sequenziellen Container, definiert Zeile 18 einen konstanten Iterator für den Vektor. Der Programmierer initialisiert ihn in der For-Schleife in Zeile 21 mit dem Ausdruck »vecIt= myVec.begin()« für den Beginn des Vektors. Nun findet die Iteration bis zum Ende des Vektors »vecIt != vecItEnd« statt. Damit man den End-Vektor »vecItEnd« verwenden kann, muss dieser die Position direkt hinter dem Vektor referenzieren. Das erledigt in Zeile 19 die Zuweisung:

std::vector<int>::const_iterator vecItEnd=myVec.end()

Der Rest der For-Schleife ist schnell erklärt: Die Inkrement-Operation »++vecIt« (Zeile 21) setzt den Iterator jeweils um eine Position weiter, der Ausdruck »*vecIt« in Zeile 22 dereferenziert die einzelnen Elemente und gibt sie aus.

Noch aufwändiger gestaltet sich die Ausgabe des assoziativen Containers in den Zeilen 32 bis 37. Dabei folgt sie dem gleichen Kochrezept: Der Code definiert gleich zu Anfang zwei Iteratoren (Zeilen 32 und 33). Dabei ist »unordIt« ein konstanter Iterator, der in der For-Schleife über alle Elementen iteriert, »unordEnd« verweist hinter das Ende des Containers. Da die Elemente des assoziativen Containers Paare sind, referenziert das Programm sie mit den Bezeichnern »first« für den Schlüssel und »second« für den Wert. Mit viel Code entsteht so das bisschen Ausgabe in Abbildung 1.

Abbildung 1: Ausgeben der Container std::vector und std::unordered_map.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

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

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • C++11

    Container sind nicht nur bei der Virtualisierung derzeit in aller Munde, auch dem Programmierer sind Behälter für Objekte nützlich. Die Version 11 von C++ enthält einige Algorithmen, die die Arbeit mit solchen Containern deutlich vereinfachen.

  • C++11

    "Performance matters": Was sich wie ein Glaubensbekenntnis anhört, bleibt ein wichtiges Designkriterium in C++. Mit den neuen Hashtabellen kann der Programmierer richtig Tempo machen.

  • C++

    Die wichtigsten Neuerungen im neuen C++17-Standard finden in den Bibliotheken statt: der leichtgewichtige String-Wrapper "string_view", die parallelisierten Algorithmen der STL, die Dateisystem-Bibliothek oder die praktischen Datentypen "std::optional" und "std::any".

  • C++11

    Klein, aber oho: Platziert ein Entwickler drei Punkte ("…") geschickt an der richtigen Stelle im C++-Code, entpacken die so genannten Variadic Templates ihre Argumente an Ort und Stelle.

  • C++11

    Die Referenz-Wrapper bilden eine kleine, aber feine neue Bibliothek in C++11. Diese Objekte verhalten sich wie Referenzen, der Artikel erklärt die Details.

comments powered by Disqus

Ausgabe 10/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.