Aperçu de la bibliothèque standard C++
Découvrez la bibliothèque standard C++, les conteneurs STL, les algorithmes et les composants essentiels du développement moderne.
La bibliothèque standard C++ (y compris la STL) fournit des composants efficaces, sûrs et prêts à l’emploi, augmentant considérablement la productivité : conteneurs, itérateurs, algorithmes, chaînes de caractères, flux d’E/S, utilitaires temporels, système de fichiers, concurrence et types utilitaires. Cet article présente les parties les plus utilisées à travers des explications courtes et des exemples fonctionnels.
1) Structure des en-têtes et inclusion de base
La bibliothèque standard est modulaire. Inclure uniquement les en-têtes nécessaires est important pour la performance et la rapidité de compilation.
<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 pointers),<optional>,<variant>,<any><thread>,<mutex>,<future>,<condition_variable>
Compilation :
MSVC : cl /std:c++20 main.cpp
GCC/Clang : g++ -std=c++20 main.cpp -o app
2) Conteneurs
Les conteneurs stockent des données, se parcourent au moyen d’itérateurs et se traitent via les algorithmes STL.
| Type | Exemples | Utilisation |
|---|---|---|
| Séquentiels | vector, array, deque, list | vector est le choix général ; array pour une taille fixe. |
| Associatifs ordonnés | map, set, multimap | Arbres triés ; recherche en O(log n) |
| Associatifs non ordonnés | unordered_map, unordered_set | Basés sur des tables de hachage ; accès moyen O(1) |
| Piles et files | queue, priority_queue, stack | Traitement FIFO/LIFO ou par priorité |
#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) Itérateurs et algorithmes
Les itérateurs abstraient les conteneurs, tandis que <algorithm> fournit des opérations génériques indépendantes du conteneur.
#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 s = 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) Ranges C++20 (brièvement)
Ranges permet d’enchaîner les algorithmes dans un style « pipeline ». Nécessite le support C++20.
#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 et regex
std::string possède sa propre mémoire ; std::string_view est une vue non possédante (attention à la durée de vie).
<regex> sert aux expressions régulières.
#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) Flux E/S (iostream, fstream, sstream)
Les flux permettent de chaîner facilement les opérations d’entrée/sortie.
fstream gère les fichiers, stringstream facilite l’analyse textuelle.
#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) Gestion du temps (chrono)
<chrono> permet de mesurer des durées et manipuler des temps.
#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) Système de fichiers (filesystem)
Fournit une gestion multiplateforme des fichiers et répertoires.
Les anciens GCC nécessitaient -lstdc++fs, ce n’est plus le cas avec les versions modernes.
#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) Nombres aléatoires (random)
Le générateur Mersenne Twister (mt19937) et les distributions modernes facilitent la génération de nombres aléatoires.
#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) Mémoire et types utilitaires
<memory> inclut les smart pointers (unique_ptr, shared_ptr, weak_ptr).
<optional> représente un « valeur ou rien », <variant> un union typé,
<any> un conteneur générique (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 << "aucun\n";
variant<int,string> v2 = 10; v2 = string("texte");
visit([](auto& t){ cout << t << "\n"; }, v2);
}
11) Concurrence (thread, mutex, future)
Fournit les primitives de base pour le multithreading et la synchronisation.
#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 << " resultat=" << fut.get() << "\n";
}
12) Outils numériques (numeric, cmath)
<numeric> fournit des fonctions d’accumulation et de réduction.
<cmath> fournit les fonctions mathématiques classiques.
#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 << "moyenne=" << avg << "\n";
}
13) Résumé rapide (Quand utiliser quoi ?)
- Conteneur polyvalent : vector
- Données triées / recherche par intervalle : map/set
- Accès rapide par hachage : unordered_map/unordered_set
- Pipeline expressif : ranges (C++20)
- Fichiers et répertoires : filesystem
- Mesures temporelles : chrono
- Valeur optionnelle sûre : optional; multi-type : variant
14) TL;DR
- La STL repose sur le trio : conteneurs + itérateurs + algorithmes.
- vector est le choix par défaut ; map/set pour des données triées, unordered_* pour des accès rapides.
- algorithm/numeric offrent des transformations génériques. Avec C++20, ranges rend le code plus lisible.
- string_view permet un accès non-copié (attention à la durée de vie des objets).
- chrono, filesystem, random simplifient les opérations système.
- Types modernes : optional, variant, any, smart pointers.
- Pour le multithreading : thread/mutex/future.
- Tous les exemples fonctionnent sous Visual Studio 2022 et GCC 11+.