Open Source im professionellen Einsatz
Linux-Magazin 04/2010
© Ablestock Premium, 123RF.com

© Ablestock Premium, 123RF.com

Der kommende C++-Standard C++0x

Erfrischend neu

An der Sprache C++ ändert sich selten etwas. Doch nun steht mit dem C++0x ein neuer Standard vor der Tür, von dem Neulinge wie Könner profitieren sollen. Mit Move-Semantik, Lambda-Funktionen und Aggregatzuweisungen bringt er viele Modernisierungen in die Programmiersprache.

766

Zwölf Jahre ist es schon her - sieht man vom ARM-C++-Standard im Jahr 1989 ab -, dass die ISO den Standard C++98 (ISO/IEC 14882) verabschiedet hat. Lediglich 2003 erfuhr er mit C++03 eine technische Korrektur. Umso gespannter darf der Programmierer auf den kommenden C++-Standard namens C++0x sein, denn dieser bringt mächtige Erweiterungen mit sich. Die Abkürzung bezieht sich auf den gescheiterten Plan, den Standard 2008/2009 zu verabschieden. Die Annahme bis zum Jahr 2011 gilt jedoch mittlerweile als sicher.

Renovierte Kernsprache

Während sich dieser Artikel vor allem den Neuerungen der Kernsprache widmet, wird ein Artikel in der nächsten Ausgabe die Neuheiten in der Bibliothek vorstellen.

C++0x bleibt folgenden Prinzipien der Programmiersprache C++ treu:

  • C++ ist eine Multi-Paradigmen-Programmiersprache [1].
  • Vertraue dem Programmierer.
  • Zahle nicht für etwas, das du nicht benutzt.
  • Brich keinen funktionierenden Code.
  • Kontrolle zur Compilezeit ist besser als zur Laufzeit.

Insbesondere soll der neue Standard eine bessere Programmiersprache für die Systemprogrammierung und die Implementierung von Bibliotheken werden. Auch an den Programmieranfänger denkt der C++-Schöpfer Bjarne Stroustrup, denn C++0x soll einfacher zu lehren und zu lernen sein. Obwohl sich C++0x laut Stroustrup wie eine neue Sprache anfühlt, bricht es nicht mit bestehendem C++-Code.

Rund um das Definieren von Klassen und deren Methoden enthält C++0x viele Verbesserungen. Sie helfen dem Novizen, seine Intention explizit auszudrücken, und dem Experten erlauben sie, das Verhalten seiner Datentypen zu optimieren. Listing 1 zeigt mehrere Klassendefinitionen, die jeweils mindestens ein neues Feature von C++0x demonstrieren.

Der Reihe nach: Instanzen der Klasse »NonCopyableClass« (Zeile 1) sind genau das, was sie versprechen, also nicht kopierbar. Nützlich ist diese Eigenschaft für die Arbeit mit Ressourcen wie Dateien, Locks oder Netzwerkverbindungen, für die sich kein sinnvolles Kopieren definieren lässt. Erreicht wird das Kopierverbot durch den Bezeichner »delete«. Während »delete« die durch den Compiler automatisch erzeugten Kopier- und Zuweisungsoperatoren in Zeile 2 und 3 unterbindet, bewirkt »default«, dass der durch den Compiler erzeugte Default-Konstruktor in Zeile 4 verwendet wird.

Mit diesen Bezeichnern lassen sich weitere bekannte C++-Idiome einfach umsetzen. So wird durch die Methode

void *operator new(std::size_t) = delete;

erzwungen, dass sich ein Objekt dieses Typs nicht mehr dynamisch mittels »new« erzeugen lässt.

Listing 1:
Klassendeklarationen

01 class NonCopyableClass{
02   NonCopyableClass & operator=(const NonCopyableClass&) = delete;
03   NonCopyableClass(const NonCopyableClass&) = delete;
04   NonCopyableClass() = default;
05 };
06 
07 class BaseClass{
08   virtual void foo();
09   void bar();
10 };
11 
12 class DerivedClass [[base_check]]: public BaseClass{
13   void foo [[override]] ();
14   void foo [[override]](int)
15   void bar [[hiding]] ();
16   void bar [[hiding]](int);
17 };
18 
19 class DelegateConstructor {
20 int value;
21 public:
22   DelegateConstructor(int v) : value(v) {}
23   DelegateConstructor() : DelegateConstructor(17) { }
24 };
25 
26 
27 class BaseClass{
28 public:
29   BaseClass(int i);
30 };
31 
32 class DerivedClass : public BaseClass{
33 public:
34   using BaseClass::BaseClass;
35 };
36 
37 template<typename T> class MyVector {
38 public:
39   MyVector(std::initializer_list<T> list);    // initializer-list constructor
40   MyVector(const MyVector&);                  // copy constructor
41   MyVector(MyVector&&);                       // move constructor
42   MyVector& operator=(const MyVector&);       // copy assignment
43   MyVector& operator=(MyVector&&);            // move assignment
44 };

Klare Verhältnisse

Es geht explizit weiter: Das Attribut »base_check« in der Klassendefinition in Zeile 12 sowie die beiden weiteren Attribute »override« und »hiding« unterbinden das zufällige Überladen oder Verstecken von Methoden der Basisklassen. Das Schlüsselwort »base_check« stellt sicher, dass jede Methode der abgeleiteten Klasse, die eine Methode der Basisklasse überlädt oder versteckt, dies ausdrücklich formuliert. Daher führt sowohl die Deklaration der Methode »foo(int)« aus Zeile 14 als auch die der Methode »void bar(int)« aus Zeile 16 zu einem Compilezeit-Fehler. Sollten in C++ alle Konstruktoren einer Klasse eine gemeinsame Initialisierungsroutine durchlaufen, war es bisher nötig, diese Routine in eine »init()«-Methode zu verpacken, sodass jeder Konstruktor sie aufrufen musste. Das ist fehleranfällig und geht nun einfacher, denn C++0x unterstützt die Delegation von Konstruktoren.

Beide Konstruktoren der Klasse »DelegateConstructor« rufen entweder direkt oder indirekt den Konstruktor »DelegateConstructor(int v)« auf, der dafür sorgt, dass »value« mit dem Wert 17 initialisiert wird. Konstruktoren lassen sich in C++0x nicht nur delegieren, sondern auch erben. Ein einfaches »using BaseClass::BaseClass« in Zeile 34 führt alle Konstruktoren der Basisklasse in die abgeleitete Klasse ein.

Die Containerklasse »MyVector« (Ähnlichkeiten mit dem C++-Datentyp »std::vector<int>« sind durchaus beabsichtigt), die über den Typ »T« parametrisiert ist, enthält zwei neue Konstruktoren. Zuallererst erlaubt der Initialiser-List-Konstruktor aus Zeile 39, dass sich »MyVector« über Sequenzen von homogenen Werten initialisieren lässt:

MyVector<int> myIntVec={1,2,3,4,5}

Die einfache Initialisierung von Standardcontainern über »{}«-Initialiser haben Programmierer schon lange vermisst. Jeder Standardcontainer besitzt diesen Initialiser-List-Konstruktor. Aber auch in eigenen Datentypen oder Funktionen lassen sich Initialiser-Listen verwenden: »double sumAll(std::initializer_list<double> list)«.

Linux-Magazin kaufen

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

Deutschland

Ähnliche Artikel

  • C++

    Mit der Move-Semantik und konstanten Ausdrücken besitzt modernes C++ eine kräftige Stellschraube, um die Performance einer C++-Anwendung in die richtige Richtung zu drehen.

  • 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.

  • C++11

    Die neuen Smart Pointer in C++11 machen den Zugriff auf Ressourcen transparent und räumen hinter sich auf. Dieser Artikel stellt als ersten Vertreter den Unique Pointer vor.

  • C++11

    Diese Folge geht ans Eingemachte von C++11: Sie zeigt, wozu Move-Semantik nützlich ist, erklärt Rvalues und Lvalues und deckt auf, was es mit dem doppelten &-Zeichen auf sich hat.

  • C++

    Beim deklarativen Programmieren drückt der C++-Programmierer unter anderem mit Hilfe von Schlüsselwörtern aus, was er erreichen möchte. Der Compiler kümmert sich dann um den weiteren Weg.

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.