Einfacher coden mit C++17: Selection Statement mit Initializer

Vorab sei kurz und bündig gesagt: C++ ist schwierig! Zum Glück hat der C++17-Standard einige neue Features, die das Schreiben von C++ Code einfacher gestalten. «Selection Statements mit Initializer» ist beispielsweise eines dieser kleinen aber feinen Features, die unseren Programmierer-Alltag angenehmer machen. In unserem Booklet zu den neuen C++ Standards beschreiben wir diese Funktion (Seite 55) – sowie alle weiteren nennenswerten Neuerungen.

Mit der Einführung von C++17 können if und switch Statements direkt innerhalb des Ausdruckes initialisiert werden – statt wie früher vor dem Statement. Variablen, die nur in der Bedingung oder innerhalb vom selection scope gebraucht werden, können ähnlich wie bei einem for loop sozusagen «in-place» initialisiert werden. In modernem C++ sieht das dann so aus:

// i wird direkt im if-statement initialisiert
if (unsigned i = std::rand(); i % 2 == 0)
{
  std::cout << "i is even" << std::endl;
} 
else 
{
  std::cout << "i is odd" << std::endl;
}

Der offensichtlichste Vorteil liegt darin, dass der Code etwas «näher zusammenrückt» und die Initialisierung gleich bei der Verwendung steht.

Aber es gibt noch weitere Vorteile: zum einen die vereinfachte Lesbarkeit und zum anderen hilft die inline-Initialisierung mit dem scoping der temporären Variablen. Früher musste das i im scope um das if–else herum deklariert werden. Mit Hilfe des Initializers verlässt das i den scope mit der schliessenden } von if bzw. von else nicht.

Das ist selbstverständlich nur dann praktisch, wenn die in der Bedingung verwendeten Variablen wirklich temporär sind und nicht nach dem Selection Statement wiederverwendet werden. Aufgrund dieses scopings sollten Initializer in Selection Statements nur mit Funktionen verwendet werden, die Werte «by value» zurückgeben – und nicht als Pointer. Es ist natürlich möglich solche Variablen von Hand innerhalb des Statements zu löschen. Dies ist aber kein schöner Programmierstil, da der Cleanup-Code in jedem Ausführungspfad korrekt wiederholt werden muss. Sei dies bei if–else oder bei den einzelnen case-Blöcken von switch-Statements.

Noch mehr Spass bringen die Initializer, wenn sie in Kombination mit structured bindings verwendet werden – einer weiteren Neuerung in C++17. So lässt sich beispielsweise ein einfach lesbarer Konsistenzcheck für ein std::tuple schreiben:

if(const auto [x,y,z] = func_returning_a_tuple(); x + y < z)
{ 
  // Do something that relies on the check above 
}

Als kleine Warnung sei hier erwähnt, dass jedes if einen neuen, möglicherweise verschachtelten scope öffnet. «Gefährlich» wird es, wenn Variablen in einem if–else neu deklariert werden und der Programmierer dies übersieht. Eine Funktion ohne Rückgabetyp (void) als Initializer zu verwenden und stattdessen die out-Parameter zu nutzen ist möglich, doch wohl kaum im Sinne der Entwickler.

Der Initializer in den Selection Statements ist weder die grösste Neuerung in C++17 noch ändert sich damit die Art, wie Code in Zukunft geschrieben wird. Nichtsdestotrotz vereinfacht die neue Funktion den Programmierer-Alltag und zeigt anschaulich, in welche Richtung sich modernes C++ entwickelt.

About Dominik Berner

Dominik Berner is a well seasoned C++ coder and agilist with a dedication to construct good, maintainable software.
This entry was posted in C++, Embedded and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *