Menü
Avatar von KaSt17
  • KaSt17

9 Beiträge seit 18.03.2017

Auf Performance MUSS eingegangen werden!

Denn Performance ist die Daseinsberechtigung von C/C++ schlechthin! Wenn Performance keine Rolle spielt, dann wählt man heutzutage eher eine andere Sprache.

Ihre propagierte switch-freie Lösung ist nicht lesbarer oder wartbarer als eine switch-basierte Lösung. switch ist ein Konstrukt der Kernsprache und drückt klar Absicht (intent) aus. Eine Datenstruktur kann das nicht leisten und Ihr Beispiel macht das schön deutlich. Ich bin mir ziemlich sicher, dass viele Programmierer die switch-Beispiele sofort erfassen. Bei dem map-Beispiel bin ich da eher skeptisch. Eine std::unordered_map ist ausschließlich eine Datenstruktur. Die Begrifflichkeit Kontrollstruktur ist in der Informatik meines Wissens kein üblicher Begriff. Ja, Datenstrukturen kann man zur Steuerung von Programmflüssen nutzen. Aber das kann letztlich auch nur Code, der sich dieser Strukturen bedient. Diese Aussage gilt nicht nur für assoziative Container.

Übrigens kann man auch mit maps unter zu Hilfenahme von Lambda-Funktionen schön schwer wartbaren Code schreibe. Ich habe mal Ihr Beispiel etwas verunstaltet, siehe https://godbolt.org/g/bs6V9u:

static const std::unordered_map<Message, std::function<void()>> mess2Func{ // (1) {Message::information, [](){ std::cerr << "message" << std::endl; }}, {Message::warning, [](){ std::cerr << "warning" << std::endl; }} };

Jetzt stellen Sie sich das bitte mal in dem von Ihnen genannten 100+-case-Szenario vor randvoll gefüllt mit nicht-trivialen Lambda-Funktionen. Hat da die map etwas verbessert? Dann doch bitte lieber die switch-Variante und alle verfügbaren switch-bezogenen Kompiler-Warnungen aktiviert (und als Fehler -Werror).

Nun zur Eingangs erwähnten Performance. Fakt ist, dass es derzeit keine constexpr-maps gibt. Oder ist Ihnen da eine Implementierung bekannt? D.h. ich kann zwar meine map const deklarieren, aber es wird ein statisches Konstruktor/Destruktur-Paar angelegt, dass 1.) die Startzeit (und Beendigung) des Programms erhöht und 2.) Code-Bloat erzeugt. Des weiteren entziehen Sie dem Compiler jegliche Möglichkeit der Optimierung! Wenn der Compiler nachweisen kann, dass bestimmte cases niemals aufgerufen werden, dann kann er diese weg optimieren. Hier ein Beispiel https://godbolt.org/g/mU1LHh. Das kann viel Codegröße und Laufzeit einsparen. Dank link-time-optimization funktioniert das auch über Compilierungseinheiten hinweg. Im Vergleich dazu nun der map-based Ansatz https://godbolt.org/g/szXdeT. Was für eine Katastrophe!

Übrigens birgt der map-basierte Ansatz auch noch ein weiteres Fehlerpotential. Hier ist Ihr Beispiel mit einem subtilen Fehler https://godbolt.org/g/TWvvS1. Viel Spaß beim Suchen. Stellen Sie sich das mal mit 100 Einträgen vor. Versuchen Sie mal, den gleichen Fehler in der switch-Variante zu erzeugen.

Abschließend möchte ich Sie eindringlich bitten, daran zu denken, wer Ihr Zielpublikum ist. Für C++-basierte Projekte ist Effizienz (Laufzeit, Code-Größe, Energieverbrauch) i.d.R. eines der wichtigen Constraints. Da kann man Effizienz nicht links liegen lassen, wenn man Alternativen zu bewährten Mitteln verkaufen will. Das mag bei Python-basierten Projekten anders sein. Sie könnten nun einwenden, dass man Software erst korrekt und wartbar entwickeln sollte und dann die kritischen Pfade optimieren. Es heißt zu Recht "avoid premature optimization", aber Ihre vorgeschlagene map-basierte Alternative zu switch fällt definitiv in die Kategorie "premature pessimization".

Mit freundlichen Grüßen,
Kai

Bewerten
- +
Anzeige