Advanced   Java   Services for-each (range based for loop C++11) Back Next Up Home


for-each (range based for loop C++11)

Ab C++11 gibt es nun auch in C++ eine for-each Schleife. Ihre Syntax ist der von Java sehr ähnlich, jedoch gibt es ein wenig mehr zu beachten als in Java. Wir müssen unterscheiden zwischen primitiven Datentypen und Klassen.


for-each mit primitiven Datentypen

Das folgende Beispiel ist am Anfang überraschend, jedoch kann man daraus sofort die richtigen Schlußfolgerungen ziehen.


Ausgeben eines int-Arrays mit for-each (Wertausgabe)

Wir betrachten den folgenden einfachen Code

void for_each_using_values()
{
   cout << endl << "Ausgabe eines Arrays mit for-each" << endl << endl;

   int intArr[] = { 0, 2, 4, 6, 8 };

   for(int elem: intArr)
      cout << elem << ' ' ;
   cout << endl << endl;

   for(int elem: intArr)
      cout << ++elem << ' ' ;
   cout << endl << endl;

   for(int elem: intArr)
      cout << elem << ' ' ;
}

Er macht die folgende Ausgabe

C++11-for-each-1.jpg

Offensichtlich ist dies eine reine Leseschleife, was bedeutet, daß elem eine Kopie des originalen Arrayelementes ist.


Ausgeben eines int-Arrays mit for-each (Ausgabe über Referenz)

Verwenden wir Referenzen, sieht das ganze so aus.

void for_each_using_references()
{
   cout << endl << "Ausgabe eines Arrays mit for-each" << endl << endl;

   int intArr[] = { 0, 2, 4, 6, 8 };
   for(int elem: intArr)
      cout << elem << ' ' ;
   cout << endl << endl;

   for(int& elem: intArr)
      cout << ++elem << ' ' ;
   cout << endl << endl;

   for(int elem: intArr)
      cout << elem << ' ' ;
   cout << endl << endl;
}

Die Ausgabe

C++11-for-each-2.jpg

Für primitive Datentypen ist das kein großer Unterschied, für Objekte allerdings ist der Unterschied gravierend. Verwendet man die erste Variante, so wird von jedem Arrayelement mit Hilfe des copy-Konstruktors eine Kopie angelegt, was zeit- und speicheraufwendig sein kann, hier lohnt es sich also mit Referenzen zu arbeiten.


for-each mit Klassentypen

Mit einer einfachen Klasse (oder struct) kann man leicht explizit zeigen, daß bei einer Wertausgabe der Kopierkonstruktor verwendet wird.


Wertausgebe eines Objekt-Arrays mit for-each

Hier unsere Testklasse.

#ifndef FOREACHTEST_H_
#define FOREACHTEST_H_

#include 

using namespace std;

namespace hms
{

   class ForEachTest
   {
   public:
      ForEachTest() {};
      ForEachTest(const ForEachTest& )
      {
         cout << "copy constructor" << endl;
      };
      virtual ~ForEachTest() {};

      //friend std::ostream& operator<< (std::ostream& stream, const ForEachTest& fet);
   };

} /* namespace hms */

#endif /* FOREACHTEST_H_ */

Wir verwenden Sie in folgendem einfachen Programm.

void for_each_using_values_of_objects()
{
   cout << endl << "for_each_value_class" << endl << endl; // prints hello world

   ForEachTest testArr[] = { ForEachTest(), ForEachTest(), ForEachTest() };

   for(ForEachTest elem: testArr)
      ;
}

Die Funktion macht die folgende Ausgabe

C++11-for-each-3.jpg


for-each mit Referenzen

Wir verwenden nun ein string-Array und zeigen, daß über Referenzen auf die Strings schreibend zugegriffen werden kann

void for_each_using_references_of_strings()
{
   cout << endl << "for_each_using_references_of_strings" << endl << endl; // prints hello world

   string stringArr[] = { "ee", "i", "o", "um" };

   for(string elem: stringArr)
      cout << elem << ' ' ;
   cout << endl;

   for(string& elem  : stringArr)
      elem.insert(0, "f");

   for(string elem: stringArr)
      cout << elem << ' ';
   cout << endl;
}

Die Funktion macht die folgende Ausgabe

C++11-for-each-5.jpg

Näheres zu "fee fi fo fum" findet man in wikipedia.


for-each mit const-Referenzen

Will man einen reinen Lesezugriff, so setzt man eine const-Referenz ein. Auf diese Weise verhindert man einen versehentlichen Schreibzugriff.

void for_each_using_const_references()
{
   cout << endl << "for_each_using_references_of_strings" << endl << endl; // prints hello world

   string stringArr[] = { "ee", "i", "o", "um" };

   for(const string& elem : stringArr)
      cout << elem << ' ' ;
   cout << endl;

// for(const string& elem: stringArr)
//    elem.insert(0, "f");  //invalid argument
}

for-each und auto (type inference)

Falls der Compiler aus dem Zusammenhang den Typ der Variablen ermitteln kann, kann man ab C++11 das (umfunktionierte) Schlüsselwort auto verwenden. Dieses type-inference genannte Feature erleichtert insbesondere den Umgang mit den Iteratoren (siehe dazu das entsprechende Kapitel). Aber auch bei den obigen Schleifen ergeben sich (kleine) Vereinfachungen.

Hier die Verwendung von auto im einfachsten Fall.

statt

int intArr[] = { 0, 2, 4, 6, 8 };
for (int elem: intArr)
   cout << elem << ' ';
cout << endl << endl;

ab C++11 auch

int intArr[] = { 0, 2, 4, 6, 8 };
for (auto elem: intArr)
   cout << elem << ' ';
cout << endl << endl;

und statt

int intArr[] = { 0, 2, 4, 6, 8 };
for (int& elem: intArr)
   cout << elem << ' ';
cout << endl << endl;

ab C++11 auch

int intArr[] = { 0, 2, 4, 6, 8 };
for (auto& elem: intArr)
   cout << elem << ' ';
cout << endl << endl;

und ebenso statt

string stringArr[] = { "ee", "i", "o", "um" };

for(const string& elem: stringArr)
   cout << elem << ' ' ;

ab C++11 auch

string stringArr[] = { "ee", "i", "o", "um" };

for(const auto& elem: stringArr)
   cout << elem << ' ' ;

Valid XHTML 1.0 Strict top Back Next Up Home