C++ von den Grundlagen bis zum Profi — Folge 18
Verzögerte Datenpipelines mit Ranges und Views aufbauen
Die Artikel in diesem Blog wurden zu Lehrzwecken verfasst. Sie können Fehler enthalten; prüfen Sie die Aussagen daher mit dem Ziel-Compiler und der verwendeten Standardbibliothek.
Iteratoren trennen Container und Algorithmen, klassische Aufrufe übergeben aber immer begin und end. C++20 Ranges akzeptieren einen ganzen Bereich; Views kombinieren verzögerte Transformationen ohne Kopie der Quelldaten.
Einen Bereich direkt übergeben
std::vector<int> scores{30, 80, 50, 100};
std::ranges::sort(scores);
auto found = std::ranges::find(scores, 80);
if (found != scores.end())
{
// Wert gefunden.
}
So können Iteratoren verschiedener Container weniger leicht vermischt werden. Eine Projection wählt auch direkt ein Member aus.
std::ranges::sort(players, {}, &Player::Score);
Eine View berechnet bei Bedarf
auto visibleNames = players
| std::views::filter([](const Player& p) { return p.IsVisible; })
| std::views::transform([](const Player& p) -> const std::string&
{
return p.Name;
})
| std::views::take(10);
for (const std::string& name : visibleNames)
DrawName(name);
Diese Pipeline erzeugt keine drei Zwischenvektoren. Filter und Transformation laufen, wenn die Iteration ein Element anfordert; take(10) stoppt nach höchstens zehn Treffern.
Die meisten Views besitzen ihre Daten nicht
auto MakeBadView()
{
std::vector<int> local{1, 2, 3};
return local | std::views::filter([](int value) { return value > 1; });
}
Die zurückgegebene View verweist auf einen lokalen vector, der beim Funktionsende zerstört wird. Eine spätere Iteration greift auf ein abgelaufenes Objekt zu.
Vor Speichern oder Rückgabe einer View muss die Quelle alle Nutzungen überleben. Braucht das Ergebnis eigenes Eigentum, wird es ausdrücklich in einen Container materialisiert.
Verzögerte Auswertung verschiebt auch Fehler und Seiteneffekte bis zur Iteration. Änderungen der Quelle unterliegen weiterhin den normalen Regeln zur Iterator-Invalidierung.
Ranges sind wertvoll, weil sie Datenfluss als Schritte ausdrücken. Wird eine Pipeline lang oder mischt Änderungen mit Abfragen, helfen benannte Zwischenstufen oder explizite Algorithmen.