C++11 - Kurzer Überblick

C++ wird kontinuierlich weiterentwickelt und typisch alle 3-4 Jahre wird ein neuer Standard veröffentlicht. Mit C++11 (2011 veröffentlicht) wurden besonders viele und weitreichende Änderungen eingeführt, die gängige Programmierprobleme betreffen bzw. vereinfachen.

Vor der Veröffentlichung war C++11 unter dem Namen C++0x bekannt. Es existiert noch zahlreiche Literatur, die den alten Namen verwendet, d.h. C++11 und C++0x sollten als Synonyme betrachtet werden. Der Standard selbst ist nur ein langes Dokument mit Spezifikationen und es ist Aufgabe verschiedener Gruppen oder Firmen entsprechende Compiler zu implementieren, die diesem Standard folgen.

Ab der GCC Version 4.8 werden fast alle Features von C++11 unterstützt, siehe (GCC C++11 Status). Details zur Unterstützung der verschiedenen C++ Versionen in der GCC Standard-Bibliothek finden sich in (libstdc++ Status). Alternativ bietet auch der populäre Open-Source Compiler Clang volle C++11-Unterstützung sowohl in der Hauptfunktionalität (Clang C++11 Status) als auch in der eigenen Version der Standard-Bibliothek (libc++ Status).

Momentan ist im CIP-Pool-Cluster (unter Linux Ubuntu 16.0.4) die GCC Version 5.4 verfügbar, diese Version unterstützt alle hier besprochenen Beispiele.

Es sollte aber erwähnt werden, dass oft einige spezielle Features verbleiben, die von den Compilern nicht unterstützt werden, z.B. unterstützt GCC immer noch nicht den vollen Umfang der alten C++98 oder C++03 Standards.

Insgesamt wurden in vielen Bereichen Änderungen gegenüber dem bisherigen Standard gemacht, die zum einen die Funktionalität erweitern aber zum andern auch die Bedienung vereinfachen oder robuster machen.

Im folgenden wird ein kleiner Teil dieser Änderungen kurz vorgestellt, Schwerpunkt ist Thread Programmierung in C++11.

Die Entwicklung geht natürlich weiter, mittlerweile gibt es die Standards C++14 und C++17, die jeweils etliche weitere Änderungen und Erweiterungen beinhalten, allerdings eher für Experten ...


auto

Neues key-word erlaubt vereinfachte Deklaration von Variablen, wenn sich die Typ-Defintion aus dem Kontext eindeutig ableiten lässt, z.B.:

// C++ 11
  map< string, string > engdeut;
  for ( auto it = engdeut.begin(); it != engdeut.end(); ++it ) { ....

// C++ 03
  map< string, string > engdeut;
  for ( map<string,string>::iterator it = engdeut.begin(); it != engdeut.end(); ++it ) { ....


for-each

Vereinfachte Schleife über Container mit direktem Zugriff auf jedes Element (for-each Loop in anderen Sprachen), z.B.

// C++ 11
  vector<double> vec1; ...
  for( auto x : vec1 ) {
    cout « x;
};

// C++ 03
  vector<double> vec1; ...
  for(int i=0; i<vec1.size(); i++) {
    cout « vec1[i];
};


tuple

Container um Objekte verschiedenen Typs und beliebiger Anzahl zu gruppieren (wie pair, aber auch für \bgroup\color{dgreen}$>=2$\egroup Objekte):

// C++ 11
tuple<int,float,string> t(1,2.f,"text");
int x = get<0>(t);
float y = get<1>(t);
string z = get<2>(t);


lambda Funktionen

sind "anonyme" Funktionen, sehr praktisch als Argument bei Aufruf von anderen Funktionen, z.B. STL Algorithmen die Funktion-Objekt bzw. Functor als Argument erwarten:

   vector <double> vec2; ....
  // lambda funktion als 3. Argument, sortiert vector nach Betrag
   sort(vec2.begin(), vec2.end(), [](double x, double y) { return abs(x)<abs(y);} );

Verschiedene Optionen auf momentane Umgebung in lambda Funktionen zuzgreifen:


Speicher-Management - Smart Pointer

Smart Pointer mit memory management ( shared_ptr)

Für bestimmte Probleme braucht man dynamisch angelegte Arrays oder Objekte, z.B. wenn Funktion Objekt zurückgeben soll.

Bisher in C++ kein automatisches Memory Management im Standard-Sprachumfang, Programmierer muss sorgfältig darauf achten alle mit new angelegten Speicherbereiche auch mit delete wieder zurückzugeben, sonst memory leaks.

Großes Problem dabei sind auch dangling pointers, d.h. Speicherbereich wurde mit delete zurückgegeben, es gibt aber noch pointer, die darauf zeigen und evt. verwendet werden.

Mit C++-11 und shared_ptr automatisches Memory Management und Referenz-Zähler.


//....
// C++-03
My3Vector * vp = new My3Vector(1.0, 2.5, -0.8 ); // dynamisch angelegter 3-Vektor
cout << vp->Length() ; 
//...
My3Vector * vp2 = vp;

delete vp; // zurueckgeben

// vp2 ?? --> dangling pointer
//....
// ---------------------------------------------------------
// C++-11
#include <memory>
//...
shared_ptr<My3Vector> vp(new My3Vector(1.0, 2.5, -0.8 )); // dynamisch angelegter 3-Vektor mit shared_ptr
cout << vp->Length() ; // wie std pointer zu verwenden

shared_ptr<My3Vector> vp2(vp);
//
// kein delete noetig, shared_ptr hat Referenz-count und raeumt automatisch auf wenn kein Verweis mehr aktiv
//

shared_ptr kann fast universell für Memory Management verwendet werden und erlaubt damit ähnlich flexible und einfache Nutzung wie in Java oder Python. Es gibt daneben auch noch unique_ptr und weak_ptr, für spezielle Memory Management Probleme.


C++11 weitere Features und Kompilieren

Es gibt darüberhinaus noch viele weitere nützliche Features, z.B.

In den meisten aktuellen Compilern ist die C++11 Funktionalität noch nicht standardmässig aktiviert, sondern muss über Optionen explizit eingeschaltet werden.

Für die Version von gcc am CIP pool geht das mittels Option -std=c++11 , d.h. z.B.

g++ -std=c++11 -o myprog myprog.cpp


GDuckeck 2019-08-01