Sie befinden sich hier : adecc » C++ und der C++Builder » Warum ist C++ so populär?

Ist C++ wieder da? Nein, denn es war nie weg!

C++ scheint wieder präsenter zu sein, einige große Firmen unterstützen plötzlich diese Sprache. Und wie immer wird kontrovers diskutiert, wenn es um C++ geht. Aber warum taucht diese Sprache wieder auf, scheint eine Wiederbelebung zu erleben? Liegt es nur am neuen Standard C++11, oder spielen auch andere Gründe eine Rolle?

In den letzten Monaten hat sich rund um IT mehr bewegt als in den Jahren zuvor: Durch Smartphones, Tablets und SmartTVs, neue Betriebssysteme und Techniken wie Touch oder sogar freie Gesten kam viel Bewegung in den ganzen IT-Markt. Außerdem spielen inzwischen natürlich Soziale Netzwerke eine nicht zu ignorierende Rolle.

Aber unsere Gesellschaft wird damit auch immer abhängiger von einer funktionierenden IT-Infrastruktur. Autos, Bahnen und Flugzeuge werden mit elektronischen Hilfsprogrammen aufgerüstet. Die Eisenbahnen fahren in immer kürzeren Abständen, Fabriken werden durch Computer gesteuert und die Logistik reduziert bisher notwendige Lagerbestände durch zeitgenaue Transporte rund um die Welt. Den meisten bekannten Systemen ist eines gemeinsam: Sie sind zumindest teilweise in der Programmiersprache C++ beziehungsweise deren Untermenge C geschrieben.

So spricht Herb Sutter, ein weltweit angesehener Experte für C++ und bei Microsoft angestellt, in einem Vortrag davon, dass Microsoft seine eigene Sprache C# liebt, aber letztlich auf C++ gebaut ist. So spricht er offen aus, was andere nur hinter vorgehaltener Hand sagen. Viele der wichtigen Microsoft Produkte, wie zum Beispiel Windows, Office, der Internet Explorer, Exchange, MS SQL, aber auch der C#- Compiler selber, sind in C++ geschrieben.

Und auch soziale Netzwerke, wie Facebook, deren Backends in großen Serverfarmen laufen, oder Googles Suchdienst wären ohne C++ sicher nicht denkbar. Diese profitieren nicht nur von der größeren Geschwindigkeit der nativen C++- Anwendungen, sondern besonders auch von dem sparsamen Umgang mit den notwendigen Ressourcen. Diese Pro­grammiersprache, von Kritikern sehr oft als veraltet oder sogar konzeptionslos bezeichnet, scheint so wieder eine größere Rolle zu spielen. So wird schon von einer Auferstehung gesprochen.

C++ punktet, auch bei Nachhaltigkeit

Tatsächlich war die Programmiersprache C++ nie weg, sie war auch nicht im Verborgenen zu einem Schattendasein verdammt. Vielmehr wurden viele wichtige Systeme weiterhin in dieser nativen, leistungsfähigen Sprache geschrieben. Keine andere Sprache bietet die Bandbreite an Möglichkeiten für Architekten und Entwickler, wird durch so viele Werkzeuge unterstützt. Gleichzeitig sind die erstellten Programme schneller und ressourcenschonender als die auf Basis der gehypten Modesprachen geschaffenen. Gerade der schonende Umgang mit den Ressourcen macht C++ so interessant beim Entwickeln von Anwendungen für Endgeräte wie Smartphones und Tablets. Hier ist die Akkulaufzeit kritisch. Und je schonender eine Applikation mit den Ressourcen umgeht, umso nutzerfreundlicher ist sie letztendlich. Aber auch im Zusammenhang mit Serverfarmen ist C++ ein Gewinn. Denn hier geht es darum, den Energiebedarf im großen Stil zu senken.

In der iX 12/2013 stand ein interessanter Bericht über das Oktobertreffen des EMEA- Zweig der „The Green Grid“- Initiative. Bei der Diskussion wurde klar, dass bei den sichtbaren Bereichen, zum Beispiel der Serverhardware und Infrastruktur der Rechenzentren sehr viele Anstrengungen unternommen werden, und auch schon viele gute Ansätze und Kataloge mit Maßnahmen existieren. Daneben gibt es aber „unsichtbare“ Energiefresser, und hier steht ineffiziente Software ganz oben. Effiziente Programme, und hier speziell native Programme, reduzieren also nicht nur die Kosten durch einen geringeren Hardwarebedarf, sie führen auch im Betrieb zu deulich niedrigeren Kosten. So sagt Herb Sutter von Microsoft auf der Konferenz „Next.Lang“ im Mai 2014 auch, dass die Zeit, in der die Programmierzeit (und letztlich die Bequemlichkeit der Programmierer), die durch Java und javaähnliche Programmiersprachen von 1995 bis 2007 im Vordergrund stand, vorbei ist. Wir brauchen ein Umdenken auf den Stromverbrauch, und letztlich wieder auf die Effizients und Performance. Und C++ ist die Sprache, die nie einen Kompromiss zwischen diesen Eigenschaften und der Bequemlichkeit gemacht hat, und hier keiner kosmetischen Korrekturen bedarf.

Wie dramitisch das ist, können wir in der erwähnten iX- Ausgabe lesen. In einer Abbildung ist zu sehen, abhängig vom Startwert, wie sich der Anteil der ITK am nationalen Gesamtenergiebedarf entwickelt. Damit verbraucht dieser Bereich heute schon nahezu 10% des erzeugten Stroms, in spätestens 10 Jahren wird es der gesamte, jetzt produzierte Strom sein, wenn es nicht zu einem Paradigmenwechsel kommt. Nur sind sich in Deutschland die Manager und Verantwortlichen der Verantwortung nicht bewusst, und überlassen diese Entscheidungen lieber weiter den Programmierern. Stattdessen beruhigt man sich mit den Maßnahmenkatalogen zur Hardware und Infrastruktur, dass die Kosten pro Server immer geringer werden, vergißt aber zu erwähnen, dass die Anzahl der Server in den Zentren immer weiter steigt.

Ist C++ überhaupt objektorientiert?

Auch die Behauptung, C++ sei „konzeptionslos“, geht fehl. Zwar ist C++ nicht ausschließlich objektorientiert. Da C eine Untermenge bleibt, ist sogar das Erstellen von vollständig strukturierten Programmen machbar. Von Anfang an war die Sprache immer eine Multiparadigmen-Sprache. Sie unterstützt also neben vielen Elementen der Objektorientierung auch Komponenten aus der Metaprogrammierung und zunehmend auch der funktionalen Entwicklung. Somit ist C++ frei von Dogmen. Dazu kommen die – in dieser Form in anderen Sprachen nicht vorhandenen – Möglichkeiten der Mehrfachvererbung sowie des Entwurfs eigener Datentypen mit allen Operatoren. Dass das Festlegen auf ein Paradigma Nachteile bringt, haben auch Vertreter der „reinen“ Sprachen erkannt. Hier sucht man jetzt nach passenden Ergänzungen. Entweder in anderen Sprachen (polyglottes Programmieren) oder durch das Erweitern der eigenen Sprache (Java mit Generics und seit Version 8 mit Lambda- Ausdrücken).

Immer aktuell

Und C++ ist auch nicht veraltet. So wurde nach einigen Jahren Abstimmung im ISO-Komitee im September 2011 der neue Standard C++11 verabschiedet. An sich hatte man es sich zwar zum Ziel gesetzt, diesen Schritt bis zum Jahr 2009 zu gehen. Aber trotz der Verspätung ist das erreichte Ergebnis dennoch stattlich. Denn der neue Standard bringt sehr viele interessante Eigenschaften und macht C++ fit für die Anforderungen der kommenden Jahre.

Viele Entwickler fragen sich natürlich zu Recht, was ihnen der neue Standard bringt. Mit einem Augenzwinkern lässt sich antworten: Programmierer müssen mal wieder etwas Neues lernen. Die neuen Eigenschaften machen C++ leistungsfähiger, helfen dem Programmierer dabei, produktiver zu sein und bieten Sprachmittel zum Reduzieren der Fehleranzahl im Programm sowie zum Verbessern der Wartungsfreundlichkeit. Wie es für C++ zu erwarten war, passt sich alles in die bisherige Entwicklung ein, so dass die bisher gültigen Programme auch mit neuen Compilern übersetzt werden können. Die Sicherung der bisherigen Investitionen ist sicher einer der wichtigsten Gründe, warum Firmen sich für die Sprachen C und C++ entscheiden. Dazu kommen noch die gute Performance der ausführbaren Programme und deren schonender Umgang mit den Rechnerressourcen.

C++11, was bringt es?

Dieser Artikel will nicht alle neuen Eigenschaften erläutern, die sowohl den Compiler, aber auch die Standardbibliothek betreffen. Dafür ist die Liste der Neuerungen zu lang. Stattdessen verdeutlichen die Beispiele einige der neuen Eigenschaften.

Da wäre zuerst die Typinferenz, durch die Umänderung des Schlüsselwortes „auto“ und dem Konzept hinter dem neuen Operator „decltype“ bei der Typdefinition. Dabei wird die Typunabhängigkeit anders als bei den dynamischen Sprachen nicht durch das Laufzeitsystem übernommen, sondern durch den Compiler. So bleibt ein großer Vorteil von C++, die strenge Typisierung, die als Garant für die Performance und Stabilität der Programme gilt, vollständig erhalten.

In diesem Beispiel wird der Variablen „it“ durch den Compiler automatisch der aus dem Zuweisungsoperator resultierende Typ „vector<int>::iterator“ zugewiesen. Außerdem ist in dem obigen Schnipsel auch die Initialisierung eines C++- Containers zu sehen, auch dieses bringt natürlich einiges an Erleichterung.

Was viele als Vereinfachung für den Programmierer sehen, bringt auch neue Möglichkeiten in der Meta­programmierung. So können heute Templates geschrieben werden, die diese Eigenschaft nutzen und damit noch unabhängiger von den verwendeten Typen sind. Hier nutzt der Zuweisungsoperator leider nichts, so dass der neue Operator „decltype“ für die Typdefinition festgelegt wurde. Der folgende Code definiert eine Codeschablone, mit der zwei beliebige Argumente addiert werden können, für die es jeweils implizite Typumwandlungen oder einen passenden +- Operator gibt.

Nun fallen zwei Dinge auf. Erstens, da die Methode keinen Rückgabewert besitzt, hat sie keinen wirklichen Sinn. Sie kann aber dazu dienen, im Quellcode sicherstellen, dass die vorher definierten Bedingungen für diese Typen eingehalten sind. Ansonsten wird ein Compilerfehler erzeugt. Zweitens hätte hier auch das im vorherigen Codebeispiel verwendete Schlüsselwort „auto“ gepasst.

Das Beispiel wurde aber bewusst so gewählt, um ein neues, als „trailing-return-type“ bezeichnetes Konzept von C++11 zeigen zu können.

Dieses Konzept dient zum Erweitern der obigen Codeschablone:

Als wichtige neue Eigenschaft wird von vielen C++-Entwicklern die neue Syntax für for- Schleifen genannt. Diese kann bei Containern verwendet werden, um diese sequentiell zu durchlaufen. Die neue Eigenschaft wird auch als „range based loop“ bezeichnet.

In dem Beispiel werden alle Elemente im Container „vecValues” als Referenz der Variable „iVal“ zugeordnet und bearbeitet. Dieses kann man natürlich auch wieder geschickt mit dem Schlüsselwort „auto“ verbinden, auch hier wird es wieder leichter, templates zu implementieren, die mit beliebigen Containern zusammenarbeiten.

Schnell, Schneller als, am Schnellsten …

Eine weitere wichtige Eigenschaft sind die Rvalues-Referenzen.

Hierzu erst ein kleiner Ausflug: Manche Leser mögen sich noch an einen Artikel erinnern, in dem der Autor belegte, dass Java-Programme schneller sind als C++-Anwendungen. Einigen Entscheidern dürfte dieser Artikel besonders im Gedächtnis haften geblieben sein, da sie ihre folgenschweren Entscheidungen auf diesem Marketingtext aufbauten. Damals wurden große Parameter in C++ per Wert übergeben, während man in Java Referenzen verwendete.

In C++ lässt sich dieses Verhalten der Parameterübergabe steuern, neben Werten und Zeigern bietet C++ die Möglichkeit, diese auch per Referenz zu übergeben. Der neue C++11- Standard gibt Entwicklern ein weiteres Instrument an die Hand. Neben den mit dem Zeichen „&&“ definierten Rvalues-Referenzen gehören hier auch die Methoden „std::move“ und „std::forward<>“ dazu. Damit sollen zwei grundsätzliche Probleme gelöst werden.

  • Das Bereitstellen einer move- Semantik für C++
  • Weiterleiten von Daten (Forwarding), ohne die Notwendigkeit zu kopieren

 

Natürlich war auch damals ein nicht manipuliertes C++-Programm schneller als die Java- Variante. Nun kann man in C++ aber sogar ein „perfect forwarding“ programmieren.In diesem Beispiel wird der Speicher, der sich hinter der Variable „strTest“ befindet, durch die Methode „forwarded_tolower“ weitergeleitet, so dass keine Kopiervorgänge mehr notwendig sind. Dabei wird „std::move“ genutzt, um aus einem Objekt ein temporäres Rvalue-Objekt zu erzeugen, was dann zurückgegeben wird. Mit „std::forward<>“ wandelt der Entwickler den Parameter, der eine normale Variable ist (LValue) in eine RValue um, damit der richtige Funktionsaufruf gefunden wird.

Dieser Mechanismus wird für die Container der Standardbibliothek bereitgestellt und kann auch von jedem Entwickler in eigenen Typen verwendet werden.

Lambda- Ausdrücke, Closures, ... funktionales in C++

Erwähnenswert sind auch die Lambda-Ausdrücke in C++11. Sie dienen zur Definition von sogenannte Closures (namenlose Funktionen). Gerade beim Ausbau von C++ für die heterogene Parallelisierung spielen die Closures eine wichtige Rolle. Aber auch sie führen dazu, dass Programme kompakter, und letztlich übersichtlicher werden können.

In C++ spielen Funktionen und Funktionsobjekte (Instanzen von Klassen mit einem entsprechenden ()- Operator) eine große Rolle. Diese werden in den Algorithmen der Standardbibliothek verwendet. In großen C++-Programmen gibt es sehr viele kleine Hilfsmethoden, die oft nicht dokumentiert sind.

Die Lambda- Ausdrücke verdanken ihren Namen dem Lambda-Kalkül, einer formalen Sprache zur Definition von Funktionen und zum Beschreiben von Parametern. Mit diesen ist es möglich, kleine Funktionen an Ort und Stelle zu definieren. Das folgende Beispiel definiert zuerst zwei Hilfsfunktionen zum Sortieren, dann die Methode, in der ein Container entweder auf- oder absteigend sortiert wird.

Durch die neuen Lambda-Ausdrücke ist es jetzt möglich, die Sortierung in einem Closure zu definieren. Dadurch verändert sich der Quelltext des obigen Beispiels, und die beiden Hilfsfunktionen fallen weg.

Ein Lambda- Ausdruck besteht generell aus vier Teilen:

  • []     die Capture- Klausel des Lambda-Ausdrucks
  • ()     Parameterliste des Lambda-Ausdrucks
  • ->    Rückgabewert des Lambda-Ausdrucks
  • {}     Block mit der Implementierung (zusammengesetzte Anweisung)

 

Für die Capture- Klausel gibt es dabei folgende Möglichkeiten, das Verhalten mit der Umwelt zu steuern

  • []     Der Lambda- Ausdruck greift nicht auf Variablen des umliegenden Gültigkeitsbereichs zu
  • [&]   Der Lambda- Ausdruck nutzt die Variablen des umliegenden Gültigkeitsbereichs als Referenz
  • [=]    Der Lambda- Ausdruck nutzt die Variablen des umliegenden Gültigkeitsbereichs als Wert

 

Generell können alle Werte genutzt werden ([&]), nur einzelne ([&x]) oder eine Liste ([&x, &y]). Dabei kann das Verhalten auch unterschiedlich sein ([&x, y]). Es können auch alle in einem Modus, einzelne aber abweichend angesprochen werden ([=, &x] oder [&, x]).

Parallel können diese Ausdrücke als Funktionsobjekt gespeichert werden, und dann zum Beispiel auch Variable vom Typ „auto“ zugewiesen werden. Dieses ist sinnvoll, wenn diese Methode mehrfach genutzt wird. Diese Variable kann dann wie eine normale Methode benutzt werden.

Es gibt darüber hinaus noch viele Erweiterungen im neuen Standard. Wichtig und nützlich sind beispielsweise noch die variadic templates, die thread-Erweiterungen, die typisierten Aufzählungen, Zufallszahlen, reguläre Ausdrücke, die Initialisierung innerhalb einer Klassendefinition, die Tupel, die Initialisierungslisten, die neuen Smartpointer (shared_ptr, unique_ptr) und die rohen Zeichenketten. Die Liste zeigt: C++ ist zurück in der Öffentlichkeit. Nun wird es auch Zeit, dass die Entwickler dem folgen, ihr Wissen auffrischen und sich mit den neuen Eigenschaften der Sprache C++ vertraut machen.

Erfreulicher Ausblick

An sich spielt es für Entwickler keine große Rolle, welche der vielen neuen Systemen und Techniken sich in Zukunft behaupten werden – wenn sich Programmierer denn der richtigen Werkzeuge bedienen. Unternehmen wollen heute nicht nur Desktop- oder Serveranwendungen mit möglichst geringen Investitionen entwickeln lassen, sondern müssen auch mobile Systeme unterstützen. In den meisten Fällen verwenden die Firmen unterschiedliche Sprachen und Umgebungen für Server-, Desktop- oder mobile Anwendungen.

Es gibt eine Reihe von C++- Compilern, viele unterstützen heute schon C++11. Einige dieser Compiler sind nur auf einer Plattform verfügbar, andere aber auch übergreifend. Trotzdem müssen in den meisten Fällen die Programme immer auf der entsprechend Plattform (neu) übersetzt werden. So entwickeln viele Firmen mit einer Windows- Version, übersetzen dann aber auf der produktiven Umgebung (Unix, Linux, …) mit einem anderen Compiler.

Einen anderen, sehr interessanten Weg geht hier die Firma Embarcadero.  Hier setzt man auf die native Unterstützung verschiedener Plattformen mit einer einzigen Entwicklungsumgebung und einer einheitlichen Codebasis. Die IDE selber läuft auf einem Windows-PC.

Hier können die entsprechenden Plattformen ausgewählt werden, für die dann Compiler bereitstehen, die den passenden nativen Code erzeugen. Über ein kleines, mitgeliefertes Zusatzprogramm können diese dann auf einen Rechner mit der gewählten Zielplattform übertragen und auf diesem ausgeführt und so auch mit dem Debugger untersucht werden.

Dadurch steht eine einheitliche Umgebung zur Verfügung. Gegenwärtig können Desktopanwendungen für 32- und 64bit-Windows für Mac OS X (32bit) erstellt werden. Mit der Version XE5 kamen mobile iOS- Programme dazu, mit der aktuellen XE6- Version auch Apps für Android. Für die Zukunft sind weitere Systeme im Gespräch.

Der neue 64bit-Windows-Compiler nutzt als Backend Clang, den C++ Familiencompiler der LLVM. Diese Architektur kann C++ auf Plattformen leichter zur Verfügung stellen. Die verwendete Clang-Version im C++Builder (XE3 - XE6) (64bit) ist 3.1, so dass große Teile des noch neuen Standards C++11 bereits unterstützt werden. Damit ist der Compiler zurück in der C++-Welt. Dies macht ihn sicher auch für Entwickler anderer Compiler interessant, die eine leistungsfähige IDE suchen, aber andere Plattformen bedienen müssen. Mitgeliefert wird die Version 1.50 der freien boost-Bibliothek.

    Drucken