Ein Überblick über C++26: die Bibliothek​

Im vorangegangenen Beitrag habe ich einen Überblick über die Kernsprache von C++26 gegeben. Heute stelle ich die Bibliothek vor.​

In Pocket speichern vorlesen Druckansicht
Bibliothek mit einem aufgeschlagenen Buch, in dem ein Stethoskop liegt.

(Bild: Chinnapong/Shutterstock.com)

Lesezeit: 4 Min.
Von
  • Rainer Grimm
Inhaltsverzeichnis

Wie schon in meinen Ausführungen zur Kernsprache von C++26 betont, kann ich auch von der Bibliothek nur einen ersten Eindruck vermitteln, da der Design-Freeze von C++26 erst im ersten Quartal 2025 erfolgen wird. Um es kurz zu machen: Die Bibliothek bietet nicht so leistungsstarke Features wie die Kernsprache. Die Codebeispiele stammen noch aus den Proposals.

Modernes C++ – Rainer Grimm

Rainer Grimm ist seit vielen Jahren als Softwarearchitekt, Team- und Schulungsleiter tätig. Er schreibt gerne Artikel zu den Programmiersprachen C++, Python und Haskell, spricht aber auch gerne und häufig auf Fachkonferenzen. Auf seinem Blog Modernes C++ beschäftigt er sich intensiv mit seiner Leidenschaft C++.

Die Funktionen rund um std::string und std::string_view machen das Verwenden dieser Funktionen bequemer.

Das Verwenden der Funktionen to_chars oder from_chars war bisher ziemlich umständlich. Man musste mit res.ec == std::errc{} den Erfolg der Konvertierung überprüfen. Mit C++26 lässt sich das Ergebnis nach bool konvertieren.

std::to_string wirft ein paar Probleme auf: "the choice of the floating-point format makes std::to_string of very limited use in practice" (Published Proposal P2587R3).

auto loc = std::locale("uk_UA.UTF-8");
std::locale::global(loc);
std::cout.imbue(loc);
setlocale(LC_ALL, "C");

std::cout << "iostreams:\n";
std::cout << 1234 << "\n";
std::cout << 1234.5 << "\n";

std::cout << "\nto_string:\n";
std::cout << std::to_string(1234) << "\n";
std::cout << std::to_string(1234.5) << "\n";

setlocale(LC_ALL, "uk_UA.UTF-8");

std::cout << "\nto_string (uk_UA.UTF-8 C locale):\n";
std::cout << std::to_string(1234) << "\n";
std::cout << std::to_string(1234.5) << "\n";

Das Programm im vorangehenden Listing zeigt, dass die Ausgabe von Gleitkommaüberladungen für iostreams inkonsistent ist. Es übernimmt den Dezimalpunkt aus der globalen C-Lokale.

Dank des Proposal P2495R3 kann ein Stringstream aus einem std::string_view erstellt werden. Im folgenden Beispiel ist ""sv ein leeres string_view-Literal.

// implicitly convertable to string_view
const mystring str;

stringstream s1(""sv);
stringstream s1(str);
s2.str(""sv);

Mit C++26 können Strings und String-Views verkettet werden.

std::string calculate(std::string_view prefix)
{
  return prefix + get_string(); // NO ERROR
}

In älteren C++-Versionen vor C++26 sind nur die Datentypen void, const void und std::nullptr_t gültig. Wenn die Adresse eines beliebigen Zeigers dargestellt werden soll, muss dieser in std::string calculate(std::string_view prefix) { return prefix + get_string(); // NO ERROR } umgewandelt werden.

double d = 123.456789;
std::format("{}", &d); // ERROR
std::format("{}", static_cast<void*>(&d)); // okay
std::format("{}", static_cast<const void*>(&d)); // okay
std::format("{}", nullptr); // okay

Mit C++26 verschwinden die Fehlermeldungen.

// pointerFormat.cpp

#include <format>
#include <iostream>

int main() {
 
     std::cout << '\n';

    double d = 123.456789;

    std::cout << std::format("{}", static_cast<void*>(&d)) << '\n';
    std::cout << std::format("{}", static_cast<const void*>(&d)) << '\n';
    std::cout << std::format("{}", nullptr) << '\n';

    std::cout << '\n';

}

Die Ausgabe des Programms sieht dann folgendermaßen aus:

std::format kann std::filesystem::path-Objekte anzeigen – wie das Beispiel aus dem Proposal P2845R8 verdeutlicht:

auto p1 = std::filesystem::path("/usr/bin");
Ja std::cout << std::format("{}", p1);                           //  /usr/bin


auto p2 = std::filesystem::path("multi\nline");
std::cout << std::format("{}", p2);                          // multi
                                                             // line


auto p3 = std::filesystem::path("multi\nline");
std::cout << std::format("{:?}", p3);                        // "multi\nline"

Dank des Formatstring "{:?}" in der letzten Zeile wird die Escape-Sequenz "\n" nicht interpretiert.

std::inplace_vector ist laut Proposal P0843R8 "ein dynamisch anpassbarer Vektor mit einer zur Compilezeit festgelegten Kapazität und zusammenhängendem eingebettetem Speicher, in dem die Elemente innerhalb des Vektorobjekts selbst gespeichert werden" ("a dynamically-resizable vector with compile-time fixed capacity and contiguous embedded storage in which the elements are stored within the vector object itself").

Dieser Container kann als direkter Ersatz für std::vector verwendet werden. Wann aber sollten inplace_vector oder vector zum Einsatz kommen?

Ein Blick in das Proposal P0843R8 liefert die Antwort:

  • Speicherzuweisung ist nicht möglich, z. B. in eingebetteten Umgebungen ohne freien Speicher, in denen nur ein Stack und das statische Speichersegment verfügbar sind.
  • die Speicherzuweisung eine inakzeptable Beeinträchtigung der Performanz darstellt, z. B. in Bezug auf die Latenz,
  • die Zuordnung von Objekten mit komplexen Lebensdauern im statischen Speichersegment erforderlich ist,
  • std::array ist keine Option, z. B. wenn nicht standardmäßige konstruierbare Objekte gespeichert werden müssen,
  • ein dynamisch anpassbares Array innerhalb von constexpr-Funktionen erforderlich ist,
  • muss der Speicherort der inplace_vector-Elemente innerhalb des inplace_vector-Objekts selbst liegen (z. B. zur Unterstützung von memcpy für Serialisierungszwecke).

Die ranges-Bibliothek erhält neue Funktionen: std::ranges::generate_random und std::ranges::concat_view.

Der Aufruf std::ranges::generate_random(fltArray, g, d) verwendet den Generator g und die Verteilung d, um die Zufallszahlen zu erzeugen. Der Aufruf ist gleichbedeutend mit der folgenden Schleife:

for(auto& el : fltArray)
el = d(e);

Seit C++11 setzt sich ein Trend fort: Immer mehr Funktionsaufrufe werden in C++ zu constexpr.

  • std::stable_sort, std::stable partition und std::inplace_merge sind in C++26 constexpr. Dies gilt auch für ihre Pendants in der ranges-Bibliothek.
  • Das Proposal P1383R2 führt aus: "This proposal amounts to a (further) liberal sprinkling of constexpr in <cmath>, together with a smattering in <complex>".

In meinem nächsten Beitrag setze ich meine Reise durch die Bibliothek in C++26 fort. (map)