Überblick über die C++-Standardbibliothek
Lernen Sie die C++-Standardbibliothek mit STL-Containern, Algorithmen und wichtigen Komponenten für moderne C++-Entwicklung.
Die C++ Standardbibliothek (einschließlich STL) bietet effiziente, sichere und gebrauchsfertige Komponenten, die die Produktivität erheblich steigern: Container, Iteratoren, Algorithmen, Zeichenketten, E/A-Streams, Zeitfunktionen, Dateisystem, Parallelität und Hilfstypen. Dieser Artikel gibt einen Überblick über die wichtigsten Teile der Bibliothek und zeigt kurze, lauffähige Beispiele.
1) Aufbau und Einbindung von Header-Dateien
Die Standardbibliothek ist modular aufgebaut. Es ist wichtig, nur die benötigten Header einzubinden, um Kompilierzeit und Speicherverbrauch zu optimieren.
<vector>,<array>,<list>,<deque><map>,<set>,<unordered_map>,<unordered_set><algorithm>,<numeric>,<iterator>,<ranges>(C++20)<string>,<string_view>,<regex><iostream>,<fstream>,<sstream><chrono>,<filesystem>,<random><memory>(Smart Pointer),<optional>,<variant>,<any><thread>,<mutex>,<future>,<condition_variable>
Kompilierung:
MSVC: cl /std:c++20 main.cpp
GCC/Clang: g++ -std=c++20 main.cpp -o app
2) Container
Container speichern Daten, werden mit Iteratoren durchlaufen und mit Algorithmen verarbeitet.
| Typ | Beispiele | Verwendung |
|---|---|---|
| Sequenziell | vector, array, deque, list | vector für allgemeinen Gebrauch; array für feste Größe. |
| Geordnet (Assoziativ) | map, set, multimap | Baumbasiert; geordneter Zugriff, O(log n) Suche. |
| Ungeordnet (Hash-basiert) | unordered_map, unordered_set | Hash-Tabellen; durchschnittlich O(1) Zugriff. |
| Queues/Stacks | queue, priority_queue, stack | FIFO-, LIFO- oder Prioritätsverarbeitung. |
#include <vector>
#include <unordered_map>
#include <iostream>
using namespace std;
int main() {
vector<int> v; v.reserve(5);
v.emplace_back(3); v.emplace_back(1); v.emplace_back(2);
unordered_map<string,int> freq;
for (int x : v) freq[to_string(x)]++;
cout << "v size=" << v.size() << ", 2 freq=" << freq["2"] << "\n";
}
3) Iteratoren und Algorithmen
Iteratoren abstrahieren den Zugriff auf Container. <algorithm> bietet generische Operationen,
die unabhängig vom Containertyp funktionieren.
#include <vector>
#include <algorithm>
#include <numeric>
#include <iostream>
using namespace std;
int main() {
vector<int> a{5,1,4,2,3};
sort(a.begin(), a.end());
int sum = accumulate(a.begin(), a.end(), 0);
auto it = find(a.begin(), a.end(), 4);
if (it != a.end()) *it = 40;
transform(a.begin(), a.end(), a.begin(),
[](int x){ return x + 10; });
for (int x : a) cout << x << ' ';
}
4) C++20 Ranges (Kurzüberblick)
Ranges ermöglichen das Verketten von Algorithmen im „Pipeline“-Stil. Erfordert C++20-Unterstützung.
#include <vector>
#include <ranges>
#include <iostream>
using namespace std;
int main() {
vector<int> v{1,2,3,4,5,6};
auto even_times10 = v
| views::filter([](int x){ return x%2==0; })
| views::transform([](int x){ return x*10; });
for (int x : even_times10) cout << x << ' ';
}
5) string, string_view und regex
std::string besitzt Speicher; std::string_view ist eine nicht besitzende Ansicht (Vorsicht bei der Lebensdauer).
<regex> ermöglicht Musterabgleiche (Reguläre Ausdrücke).
#include <string>
#include <string_view>
#include <regex>
#include <iostream>
using namespace std;
bool is_email(string_view s) {
static const regex re(R"((\w+)(\.\w+)*@(\w+)(\.\w+)+)");
return regex_match(s.begin(), s.end(), re);
}
int main() {
string name = "Ada Lovelace";
string_view view = name;
cout << view.substr(0, 3) << "\n";
cout << boolalpha << is_email("dev@example.com") << "\n";
}
6) Ein-/Ausgabe-Streams (iostream, fstream, sstream)
Streams lassen sich mit Operatoren verketten. fstream liest/schreibt Dateien,
stringstream dient der Textanalyse.
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ofstream out("data.txt");
out << "42, Modern C++\n"; out.close();
ifstream in("data.txt");
string line; getline(in, line);
stringstream ss(line);
int id; char comma; string title;
ss >> id >> comma; getline(ss, title);
cout << "id=" << id << " title=" << title << "\n";
}
7) Zeitmessung (chrono)
Mit <chrono> lassen sich Zeitspannen messen und Datums-/Zeitoperationen durchführen.
#include <chrono>
#include <iostream>
using namespace std;
int main() {
using namespace chrono;
auto t0 = steady_clock::now();
for (volatile int i=0;i<1000000;i++) {}
auto t1 = steady_clock::now();
cout << "ms=" << duration_cast<milliseconds>(t1 - t0).count() << "\n";
}
8) Dateisystem (filesystem)
Plattformunabhängige Datei- und Ordneroperationen. In älteren GCC-Versionen war -lstdc++fs erforderlich,
bei modernen Compilern nicht mehr.
#include <filesystem>
#include <iostream>
using namespace std;
namespace fs = std::filesystem;
int main() {
for (const auto& e : fs::directory_iterator(".")) {
cout << e.path().filename().string() << "\n";
}
}
9) Zufallszahlen (random)
Moderne C++-Implementierungen verwenden den Mersenne-Twister (mt19937) und Verteilungen.
#include <random>
#include <iostream>
using namespace std;
int main() {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dist(1, 6);
for (int i=0;i<5;i++) cout << dist(gen) << ' ';
}
10) Speicherverwaltung und Hilfstypen
<memory> bietet Smart Pointer (unique_ptr, shared_ptr, weak_ptr).
<optional> repräsentiert „Wert oder leer“, <variant> ist ein typensicheres Union,
und <any> erlaubt typunspezifische Speicherung (type-erasure).
#include <memory>
#include <optional>
#include <variant>
#include <iostream>
using namespace std;
optional<int> parse_pos_int(int x) { return x>=0 ? optional<int>(x) : nullopt; }
int main() {
auto p = make_unique<int>(42);
cout << *p << "\n";
if (auto v = parse_pos_int(-7)) cout << *v; else cout << "leer\n";
variant<int,string> v2 = 10; v2 = string("Text");
visit([](auto& t){ cout << t << "\n"; }, v2);
}
11) Nebenläufigkeit (thread, mutex, future)
Grundlegende Mehrfach-Threading-Klassen und Synchronisationsmechanismen.
#include <thread>
#include <mutex>
#include <future>
#include <iostream>
using namespace std;
mutex m; int counter = 0;
void work(int n){
lock_guard<mutex> lk(m);
counter += n;
}
int main() {
thread t1(work, 1), t2(work, 2);
t1.join(); t2.join();
auto fut = async(launch::async, []{ return 40 + 2; });
cout << "counter=" << counter << " ergebnis=" << fut.get() << "\n";
}
12) Numerische Werkzeuge (numeric, cmath)
<numeric> bietet Summierung und Aggregation, <cmath> stellt mathematische Funktionen bereit.
#include <vector>
#include <numeric>
#include <iostream>
using namespace std;
int main() {
vector<double> x{1.0, 2.0, 3.0};
double avg = accumulate(x.begin(), x.end(), 0.0) / x.size();
cout << "durchschnitt=" << avg << "\n";
}
13) Schnellreferenz (Wann was verwenden?)
- Allgemeiner Container: vector
- Sortierte Schlüssel-Wert-Paare: map/set
- Schneller Hash-Zugriff: unordered_map/unordered_set
- Datenströme / Pipelines: ranges (C++20)
- Dateien und Verzeichnisse: filesystem
- Hochauflösende Zeitmessung: chrono
- Sicheres Optional: optional; Mehrtypwert: variant
14) TL;DR
- STL basiert auf dem Trio: Container + Iteratoren + Algorithmen.
- vector ist die Standardwahl; map/set für geordnete Daten, unordered_* für schnelle Zugriffe.
- algorithm/numeric bieten generische Datenverarbeitung; C++20 ranges erhöhen Lesbarkeit.
- string_view bietet zero-copy Zugriff (Lebensdauer beachten).
- chrono, filesystem, random erleichtern Systemaufgaben.
- Moderne Helfer: optional, variant, any, smart pointers.
- Für Nebenläufigkeit: thread/mutex/future; in Performance-kritischen Bereichen mit Bedacht einsetzen.
- Alle Beispiele sind mit Visual Studio 2022 und GCC 11+ kompatibel.