🔝 Retour au Sommaire
🎯 Niveau : Intermédiaire
Ce module couvre les évolutions qui ont transformé C++ d'un langage à gestion manuelle en un langage expressif avec gestion automatique des ressources, sémantique de valeur, et abstractions zero-cost. Smart pointers, move semantics, lambdas, puis un tour complet des nouveautés C++17 à C++26 — structured bindings, std::optional, std::expected, ranges, concepts, coroutines, contrats, réflexion statique, pattern matching, std::execution. C++26 est traité ici comme standard ratifié, avec l'état réel du support GCC 15 / Clang 20.
- Maîtriser les smart pointers (
std::unique_ptr,std::shared_ptr,std::weak_ptr) comme remplacement systématique denew/delete. - Comprendre la sémantique de mouvement (l-values vs r-values,
std::move,std::forward) et son impact sur la performance et le design d'API. - Implémenter des lambdas avec les différents modes de capture et les combiner avec les algorithmes STL et
std::function. - Utiliser les ajouts C++17 en code courant : structured bindings,
std::optional,std::variant,std::any. - Appliquer les concepts (C++20) pour contraindre les templates, et les ranges pour composer des pipelines de traitement.
- Exploiter les ajouts C++23 en production :
std::expected,std::print/std::format,std::flat_map,std::mdspan,std::generator,std::stacktrace. - Connaître les grandes nouveautés C++26 ratifiées : contrats, réflexion statique, pattern matching,
std::execution(Senders/Receivers).
- Module 2, chapitre 5 : gestion mémoire manuelle (stack/heap,
new/delete, pointeurs, dangling pointers) — les smart pointers sont une abstraction au-dessus de ce modèle. - Module 3, chapitre 6 : Rule of Five (constructeurs de copie/déplacement, opérateurs d'affectation) — la move semantics étend directement ces concepts.
- Module 3, chapitre 7 : polymorphisme dynamique et vtable — nécessaire pour comprendre le coût comparé des approches statiques (concepts, CRTP) vs dynamiques.
Remplacement complet de new/delete par des smart pointers. Ce chapitre établit la règle fondamentale du C++ moderne : aucun new/delete nu dans le code applicatif.
std::unique_ptr: possession exclusive, transfert de propriété viastd::move, custom deleters pour les ressources non-mémoire (file descriptors, handles).std::shared_ptretstd::weak_ptr: comptage de références, coût de l'atomic increment/decrement, cycles de références et commentstd::weak_ptrles casse.std::make_uniqueetstd::make_shared: pourquoi les préférer ànew— exception safety et allocation optimisée (single allocation pourmake_shared).- Règle : ne jamais utiliser
new/deletedans du code moderne — les seules exceptions sont les custom allocators et l'interopérabilité C.
La move semantics permet de transférer les ressources d'un objet à un autre sans copie. C'est l'optimisation la plus impactante introduite par C++11 — elle change la façon dont on conçoit les API et les conteneurs.
- L-values vs R-values (
&&) : catégories de valeur en C++, quand le compilateur peut déplacer automatiquement. std::move: ne déplace rien — c'est un cast vers une r-value reference qui autorise le déplacement. L'objet source est laissé dans un état valide mais indéterminé.- Move constructors et move assignment operators : implémentation, interaction avec la Rule of Five.
- Perfect forwarding avec
std::forward: préserver la catégorie de valeur dans les templates — utilisé dansstd::make_unique,emplace_back, etc. - RVO (Return Value Optimization) et Copy Elision : quand le compilateur élimine le move lui-même — mandatory copy elision depuis C++17.
Les lambdas sont le mécanisme principal pour passer du comportement aux algorithmes STL. Ce chapitre couvre la syntaxe, les modes de capture, les lambdas génériques, et std::function.
- Syntaxe et captures : par valeur (
[=]), par référence ([&]), capture dethis, captures mixtes, init captures (C++14) pour le move-capture. - Lambdas génériques (C++14) :
autodans les paramètres, templated lambdas (C++20) avec paramètres de template explicites. - Utilisation avec les algorithmes STL :
std::sort,std::transform,std::find_if,std::remove_if— les lambdas remplacent les foncteurs. std::function: type-erased callable wrapper — utile pour stocker des callbacks, mais avec un coût (allocation heap possible, indirection).
Tour complet des ajouts au langage et à la librairie standard sur quatre itérations du standard. C'est le chapitre le plus large du module — il couvre 14 sections allant des structured bindings (C++17) aux Senders/Receivers (C++26).
- C++17 : structured bindings,
std::optional/std::variant/std::any. - C++20 :
std::span(vue zero-copy sur données contiguës), concepts (contraintes sur templates remplaçant SFINAE), ranges (pipelines avec|), coroutines (co_await, co_yield, co_return), modules (état de maturité en 2026). - C++23 :
std::print/std::format(formatage type-safe),std::expected(gestion d'erreurs sans exceptions),std::flat_map/std::flat_set(conteneurs cache-friendly),std::mdspan(vues multidimensionnelles),std::generator(coroutines simplifiées),std::stacktrace(traces d'exécution standard). - C++26 (ratifié) : contrats (préconditions, postconditions, assertions), réflexion statique (introspection à la compilation), pattern matching (
inspect,is),std::execution(Senders/Receivers — modèle d'asynchronisme standardisé remplaçantstd::async/std::future), état du support GCC 15 / Clang 20.
📎
std::spanest introduit ici ; la couverture détaillée est en section 13.5.std::printest approfondi ici ; la prise en main rapide est en section 2.7.
-
std::shared_ptrcyclique sansstd::weak_ptr. Deuxshared_ptrqui se référencent mutuellement ne seront jamais libérés — le compteur de références ne tombe jamais à zéro. C'est un memory leak que Valgrind détecte mais que le programme ne signale pas autrement. Dès qu'une relation est non-owning (parent→enfant est owning, enfant→parent est non-owning), utilisezstd::weak_ptr. -
std::movesur un objetconst.std::move(const_obj)compile sans erreur ni warning — mais produit une copie, pas un déplacement. Leconstempêche le compilateur de sélectionner le move constructor (qui prend unT&&non-const). Le résultat est une dégradation silencieuse de performance. Si vous marquez un objetconst, ne lestd::movepas. -
Capture par référence dans une lambda qui survit à la portée capturée. Une lambda qui capture
[&]et qui est stockée dans un callback, retournée par une fonction, ou passée à un thread accède à des références pendantes dès que la portée d'origine se termine. Le résultat est un undefined behavior silencieux — pas de crash garanti, juste des données corrompues. Règle : si la lambda survit à la portée, capturez par valeur ou par move (init capture :[x = std::move(obj)]). -
Confondre Concepts (C++20) et SFINAE. Les concepts remplacent SFINAE pour contraindre les templates, mais ils ne fonctionnent pas de la même manière. SFINAE est un mécanisme de substitution qui écarte les overloads invalides ; les concepts sont des prédicats nommés évalués avant la substitution. Un concept qui échoue produit un message d'erreur clair, là où SFINAE produit des erreurs de substitution cryptiques. Dans du code nouveau, préférez systématiquement les concepts — SFINAE reste nécessaire uniquement pour le code pre-C++20.
À l'issue de ce module, vous savez :
- Écrire du code C++ sans aucun
new/deletenu, en utilisant exclusivement les smart pointers. - Optimiser les transferts de ressources avec la move semantics et identifier les cas où RVO rend le move inutile.
- Écrire des lambdas avec le mode de capture approprié et les combiner avec les algorithmes STL.
- Utiliser les ajouts C++17 (
std::optional,std::variant, structured bindings) et C++23 (std::expected,std::print,std::flat_map) en code de production. - Contraindre des templates avec des concepts (C++20) au lieu de SFINAE.
- Composer des pipelines de traitement avec les ranges (C++20).
- Positionner les nouveautés C++26 (contrats, réflexion statique, pattern matching,
std::execution) dans votre architecture.