Die Entwicklung einer eigenen C++ Standardbibliothek ist eine ambitionierte Aufgabe, die viele Entwickler vor große Herausforderungen stellt. Im zweiten Teil einer fortlaufenden Serie gewährt Jussi Pakkanen, der unter anderem als Schöpfer des Meson Build-Systems bekannt ist, spannende Einblicke in sein Selbstexperiment, bei dem er aus Interesse und Spaß an der Sache eine eigene C++ Standardbibliothek entwarf und umsetzte. Anders als häufig angenommen, handelt es sich dabei nicht um eine vollständige Replikation der von der ISO festgelegten Standardbibliothek, sondern um eine Sammlung von low-level Funktionen und Typen, die in vielen Anwendungen grundlegend gebraucht werden. Jussi macht gleich zu Beginn deutlich, dass das Projekt nicht missverstanden werden sollte: Es geht nicht darum, ein offizielles, genormtes Produkt zu erstellen, sondern um einen praktischen und explorativen Ansatz. Ein zentrales Thema, das in der Diskussion rund um die Eigenentwicklung von Bibliotheken immer wieder auftaucht, ist die enorme Komplexität bestehender Container-Implementierungen.
Diese müssen eine Vielzahl von Problemen adressieren, darunter der Umgang mit Typen, die nicht noexcept-moveable oder noexcept-copiable sind. Solche Bedingungen bringen oft umfangreiche Rollback-Mechanismen mit sich, die von jedem inkludierten Header ausgeführt werden müssen – ein Aufwand, der sich bei Templates besonders stark bemerkbar macht. Diese Komplexität ist einer der Hauptgründe, warum sich viele Entwickler scheuen, eigene Container zu schreiben, da man sich ohne Jahrzehnte der Härtung mit einer Vielzahl von Fehlerquellen und instabiler Logik konfrontiert sieht. Ein durchaus innovativer Ansatz in Jussis Implementierung ist daraus entstanden, dass seine Bibliothek keine Rücksicht auf die Unterstützung aller denkbaren Typen nimmt. Stattdessen setzt sie auf eine sogenannte Konzept-Definition, die fordert, dass ein Typ mindestens noexcept-moveable sein muss.
Indem ausschließlich Typen, die dieses Wohlverhalten – "WellBehaved" – zeigen, akzeptiert werden, entfällt der gesamte Aufwand, den man sonst für schlecht benommene Typen betreiben müsste. Diese Einschränkung ermöglicht eine drastische Vereinfachung der Implementierung und eliminiert eine große Menge fehleranfälligen Codes. Für Entwickler, die dennoch mit komplizierteren oder nicht ganz so „well-behaved“ Typen arbeiten müssen, gibt es einfache Workarounds, zum Beispiel die Verwendung von unique_ptr, die bei einem Performance-Verzicht als vertretbar angesehen wird. Die Diskussion um Container, Typen und Fehlertoleranz offenbart auch die pragmatische Haltung hinter dem Projekt. Wer extrem performancekritisch ist und gleichzeitig stark eingeschränkte Typen verwenden muss, wird vermutlich ohnehin gezwungen sein, eine eigene maßgeschneiderte Lösung zu erarbeiten.
Für sämtliche komprimierenden Anwendungen sind die klassischen, hochoptimierten Bibliotheken ohnehin meist die bessere Wahl. Jussi bringt es auf den Punkt: Die Bibliothek richtet sich nicht an den Mainstream, sondern an die, die experimentieren und Lernprozesse durchlaufen wollen — mit einer Grundvoraussetzung an Typenwohlverhalten. Ein weiteres Problemfeld ist das Iterieren und Aufteilen von Strings, ein Thema, das in nicht verwalteten Sprachen wie C++ erheblich komplexer ist als in Sprachen wie Python mit ihren einheitlichen Stringtypen. Die Frage, was eine geeignete Rückgabeform für eine String-Split-Funktion sein sollte, lässt sich nicht mit einem einfachen Konzept lösen: Soll die Funktion einen Vektor aus Strings zurückliefern, eine Sammlung von string_views, einen Coroutine-Handle oder eine komplett generische Lösung, die mit unterschiedlichen Stringtypen arbeitet? Jussi beschreibt hier zwei Varianten. Die erste ist die pragmatische und unkomplizierte Version, die einfach einen Vektor von Strings zurückgibt.
Die zweite ist eine abstraktere, verzögerte, speicherallokationsfreie Implementierung, die auf die Nutzung von void-Pointern zurückgreift – ein oft kritisierter, aber hier cleverer und pragmatischer Kompromiss. Diese Variante ermöglicht maximale Flexibilität ohne großen technischen Overhead, setzt jedoch voraus, dass der Nutzer mit einem kleinen Adapter-Lambda arbeitet, das diese Funktion auf passende Weise verwendet. Dieses Beispiel steht exemplarisch für ein weitverbreitetes Dilemma in nativen Programmiersprachen: Effizienz und Flexibilität stehen in einem Spannungsverhältnis zu Benutzerfreundlichkeit und Einfachheit. Jussi wählt bewusst pragmatische Lösungen, wobei er klar macht, dass kein Königsweg existiert und die Wahl der Implementierung immer vom konkreten Anwendungsfall abhängt. Ein weiterer spannender Aspekt ist die Übertragung von Iterationskonzepten aus Hochsprachen wie Python in den C++-Kosmos.
Das Python-Itertionsprotokoll ist einfach: Ein Objekt stellt eine next()-Methode bereit, die entweder den nächsten Wert zurückgibt oder eine spezielle StopIteration-Ausnahme wirft. In C++ sind Ausnahmen in vielen Fällen zu teuer, sodass stattdessen optionale Werte zurückgegeben werden. Jussi zeigt eine funktionierende Lösung auf Basis von optionalen Typen, mit der sich beispielsweise die Python-Range-Funktion nachbilden lässt. Obwohl die Integration in native Schleifenstrukturen unter Verwendung von Makros etwas umständlich erscheint, demonstriert das Projekt die Machbarkeit dieses Konzeptes in C++ und öffnet damit neue Perspektiven für komfortablere, aber dennoch effiziente Iterationsmechanismen. Vom Stand des Projekts kann gesagt werden, dass bereits grundlegende Funktionalitäten für Strings, einschließlich erzwungener UTF-8-Konformität, reguläre Ausdrücke sowie einfache Container vorhanden sind.
Das gesamte Projekt ist schlank gehalten: Der vollständige Build-Prozess umfasst gerade einmal acht einzelne Kompilations- und Link-Schritte und benötigt mit einem Kern auf einem üblichen Laptop circa 0,8 Sekunden. Diese kurzen Kompilierzeiten sind ein großer Vorteil und verdeutlichen den Erfolg der Simplifizierungen und bewussten Designentscheidungen des Projekts. Dabei muss aber erwähnt werden, dass bei der Implementierung der regulären Ausdrücke auf eine externe Bibliothek namens ctre zurückgegriffen wird, die vorcompiliert eingebunden wird. Dies stellt einen kleinen Kompromiss dar, der jedoch die eigene Entwicklungszeit reduziert und die Leistungsfähigkeit erhöht. Abschließend lässt sich festhalten, dass ein eigenes C++ Standardbibliotheks-Framework nicht nur eine interessante Lern- und Experimentierplattform bietet, sondern gleichzeitig traditionelle Annahmen hinterfragt und innovative Gedanken zur Vereinfachung und Strukturierung komplexer Bibliothekslogiken bereitstellt.
Die Entscheidung, auf konsequent wohlverhaltene Typen zu setzen und Iterations- sowie Stringoperationen pragmatisch und flexibel zu gestalten, ermöglicht eine robuste, leicht verständliche und performante Grundlage, die sowohl für Anwendungen mit hohen Anforderungen als auch für Experimentatoren spannend sein kann. Das Projekt von Jussi Pakkanen zeigt deutlich, dass das Schreiben von Softwareprinzipien, die viele als zu komplex oder als gegeben hinnehmen, durchaus lohnenswert und bereichernd sein kann. Es fordert Entwickler auf, bewusste Entscheidungen bei der Wahl ihrer Werkzeuge zu treffen, sich mit der Grundlage der Programmiersprache auseinanderzusetzen und neue Wege zu beschreiten, um die C++-Welt weiterhin aktiv mitzugestalten und weiterzuentwickeln.