Skip to content

Commit 0266d55

Browse files
committed
C++ Vector bool
1 parent d99ee50 commit 0266d55

7 files changed

Lines changed: 818 additions & 79 deletions

File tree

_articles/c++_attributes.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
layout: article
3-
title: Attributs en C++
3+
title: Les attributs (C++11)
44
permalink: articles/c++/attributes
55
category: c++
66
logo: c++.svg
@@ -23,7 +23,7 @@ En somme, il s'agit d'expliciter une intention qui **n'altère pas la logique**
2323

2424
## Historique
2525

26-
Avant l'arrivée des attributs (en C++11), chaque compilateur proposait sa propre manière de définir ces métadonnées, avec des syntaxes qui leur sont propres, **spécifiques** à chaque compilateur et **incompatibles** entre elles:
26+
Avant l'arrivée des attributs (**en C++11**), chaque compilateur proposait sa propre manière de définir ces métadonnées, avec des syntaxes qui leur sont propres, **spécifiques** à chaque compilateur et **incompatibles** entre elles:
2727

2828
- **Microsoft (MSVC)** utilise le mot-clef [``__declspec(...)``](https://learn.microsoft.com/en-us/cpp/cpp/declspec).
2929
Exemples: [``align(N)``](https://learn.microsoft.com/en-us/cpp/cpp/align-cpp) (alignement), [``dllexport``/``dllimport``](https://learn.microsoft.com/en-us/cpp/cpp/dllexport-dllimport) (exportation/importation), [``novtable``](https://learn.microsoft.com/en-us/cpp/cpp/novtable) (optimisation désactivant la vtable).
@@ -81,7 +81,7 @@ C++17 introduit la syntaxe ``using`` au début de la liste d'attributs pour spé
8181

8282
### Positionnement dans les lambdas (Depuis C++11 / C++23)
8383

84-
Le positionnement des attributs dans une lambda **dépend de la version du standard et de la cible de l'attribut** ([cppreference](https://en.cppreference.com/w/cpp/language/lambda)):
84+
Le positionnement des attributs dans une lambda **dépend de la version du standard et de la cible de l'attribut** ([cppreference](https://en.cppreference.com/cpp/language/lambda)):
8585

8686
[captures] &lt;tparams&gt;<sup>(optional)</sup> t-requires<sup>(optional)</sup> **front-attr**<sup>(optional)</sup> (params) specs<sup>(optional)</sup> except<sup>(optional)</sup> **back-attr**<sup>(optional)</sup> trailing<sup>(optional)</sup> requires<sup>(optional)</sup> contract-specs<sup>(optional)</sup> { body }
8787

@@ -254,7 +254,7 @@ Puisque le calcul de ``y`` nécessite la valeur de ``x``, le CPU et le compilate
254254
Sur [ARM](https://developer.arm.com/documentation/102336/latest/) et [PowerPC](https://www.kernel.org/doc/Documentation/memory-barriers.txt), cette garantie de dépendance de données s'applique au niveau matériel, y compris pour les accès mémoire via des pointeurs. Si vous lisez un pointeur puis lisez une valeur pointée par ce pointeur, le processeur garantit naturellement l'ordre des lectures sans barrière mémoire.
255255

256256
Imaginons le scénario d'une liste chaînée partagée entre deux threads:
257-
{% highlight cpp %}
257+
{% highlight cpp linenos %}
258258
struct Node
259259
{
260260
int value;
@@ -332,7 +332,7 @@ Grâce à cette déclaration, le compilateur sait qu'il peut compiler l'appel de
332332

333333
En pratique, l'analyse statique des dépendances de données à travers les optimiseurs s'est révélée d'une complexité insurmontable pour les concepteurs de compilateurs. Suivre précisément le graphe d'instructions sans interrompre la dépendance (ce qui arrive par exemple si un pointeur est converti en entier puis restauré) s'est avéré trop instable.
334334

335-
C'est pourquoi, depuis l'introduction de cette mécanique en C++11, la totalité des compilateurs modernes (GCC, Clang, MSVC) ont choisi de ne pas suivre ces chaînes de dépendances: le modèle ``consume`` y est silencieusement promu en [modèle mémoire ``acquire``](https://en.cppreference.com/w/cpp/atomic/memory_order), et l'attribut ``[[carries_dependency]]`` y est tout simplement [ignoré](https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Consume_ordering).
335+
C'est pourquoi, depuis l'introduction de cette mécanique en C++11, la totalité des compilateurs modernes (GCC, Clang, MSVC) ont choisi de ne pas suivre ces chaînes de dépendances: le modèle ``consume`` y est silencieusement promu en [modèle mémoire ``acquire``](https://en.cppreference.com/cpp/atomic/memory_order), et l'attribut ``[[carries_dependency]]`` y est tout simplement [ignoré](https://en.cppreference.com/cpp/atomic/memory_order#Release-Consume_ordering).
336336

337337
Puisque cet attribut n'était plus qu'une coquille vide jamais implémentée de manière effective, le comité du C++ a officiellement voté sa suppression de la norme C++26 ([**proposal**](https://wg21.link/p2738r1)).
338338

@@ -811,7 +811,7 @@ En résumé: C'est la manière la plus propre de lier le retour non pas à "la f
811811

812812
### ``[[indeterminate]]`` (C++26)
813813

814-
Avant C++26, les **variables locales [automatiques](/articles/c++/auto#automatic-storage-duration-specifier-avant-c11-obsolète)** (non ``static`` ni ``thread_local``) (comme les [**types fondamentaux**](/articles/c++/fundamental_types) ou les tableaux) déclarées **sans initialiseur** n'étaient [**pas initialisées par défaut**](/articles/c++/uniform_initialization#variable-déclarée-mais-pas-initialisée): elles contenaient des **valeurs arbitraires** (déchets de la stack) et leur **lecture accidentelle** provoquait un **[comportement indéfini (UB)](https://en.cppreference.com/w/cpp/language/ub#Uninitialized_scalar)**.
814+
Avant C++26, les **variables locales [automatiques](/articles/c++/auto#automatic-storage-duration-specifier-avant-c11-obsolète)** (non ``static`` ni ``thread_local``) (comme les [**types fondamentaux**](/articles/c++/fundamental_types) ou les tableaux) déclarées **sans initialiseur** n'étaient [**pas initialisées par défaut**](/articles/c++/uniform_initialization#variable-déclarée-mais-pas-initialisée): elles contenaient des **valeurs arbitraires** (déchets de la stack) et leur **lecture accidentelle** provoquait un **[comportement indéfini (UB)](https://en.cppreference.com/cpp/language/ub#Uninitialized_scalar)**.
815815

816816
{% highlight cpp %}
817817
void crashOrVulnerability()
@@ -851,7 +851,7 @@ void process()
851851

852852
> Le compilateur reste libre de l'ignorer et d'initialiser quand même la variable par sécurité, conformément à la [règle d'ignorabilité](#la-règle-dignorabilité) des attributs.
853853
854-
Si l'exemption est prise en compte, la variable retrouve son comportement historique: son contenu est indéterminé, et toute lecture avant écriture redevient un **[comportement indéfini (UB)](https://en.cppreference.com/w/cpp/language/ub#Uninitialized_scalar)**.
854+
Si l'exemption est prise en compte, la variable retrouve son comportement historique: son contenu est indéterminé, et toute lecture avant écriture redevient un **[comportement indéfini (UB)](https://en.cppreference.com/cpp/language/ub#Uninitialized_scalar)**.
855855

856856
### ``[[optimize_for_synchronized]]`` (TM TS)
857857

@@ -861,7 +861,7 @@ La mémoire transactionnelle permet d'exécuter des blocs de code de manière at
861861

862862
#### Le mot clef experimental ``synchronized``
863863

864-
Pour délimiter les zones critiques sans manipuler manuellement de verrous (comme ``std::mutex``), cette spécification introduit le mot clef expérimental [``synchronized``](https://en.cppreference.com/w/cpp/language/transactional_memory#Synchronized_blocks). Un bloc de code marqué ``synchronized { ... }`` s'exécute sous **exclusion mutuelle**: le résultat final est équivalent à une exécution séquentielle (un bloc ``synchronized`` après l'autre).
864+
Pour délimiter les zones critiques sans manipuler manuellement de verrous (comme ``std::mutex``), cette spécification introduit le mot clef expérimental [``synchronized``](https://en.cppreference.com/cpp/language/transactional_memory#Synchronized_blocks). Un bloc de code marqué ``synchronized { ... }`` s'exécute sous **exclusion mutuelle**: le résultat final est équivalent à une exécution séquentielle (un bloc ``synchronized`` après l'autre).
865865

866866
{% highlight cpp %}
867867
void process(int value)
@@ -880,7 +880,7 @@ Lorsqu'un bloc ``synchronized`` appelle une fonction **non [inlinée](https://fr
880880

881881
#### L'attribut experimental ``[[optimize_for_synchronized]]``
882882

883-
L'attribut [``[[optimize_for_synchronized]]``](https://en.cppreference.com/w/cpp/language/attributes/optimize_for_synchronized) résout ce problème. Il est indispensable lorsque le corps de la fonction **n'est pas connu dans la [translation unit](/articles/c++/translation_unit) courante**: il indique au compilateur (si l'attribut est [honoré](#la-règle-dignorabilité)) qu'une version optimisée pour les transactions sera bien disponible lors de l'édition de liens.
883+
L'attribut [``[[optimize_for_synchronized]]``](https://en.cppreference.com/cpp/language/attributes/optimize_for_synchronized) résout ce problème. Il est indispensable lorsque le corps de la fonction **n'est pas connu dans la [translation unit](/articles/c++/translation_unit) courante**: il indique au compilateur (si l'attribut est [honoré](#la-règle-dignorabilité)) qu'une version optimisée pour les transactions sera bien disponible lors de l'édition de liens.
884884

885885
{% highlight cpp %}
886886
// Indique au compilateur d'optimiser cette fonction pour l'appel transactionnel
@@ -895,7 +895,7 @@ void process()
895895
}
896896
{% endhighlight %}
897897

898-
Grâce à cet attribut, le compilateur génère deux versions distinctes de la fonction dans le binaire (un mécanisme appelé [**transaction clone**](https://en.cppreference.com/w/cpp/language/transactional_memory) ou clonage transactionnel):
898+
Grâce à cet attribut, le compilateur génère deux versions distinctes de la fonction dans le binaire (un mécanisme appelé [**transaction clone**](https://en.cppreference.com/cpp/language/transactional_memory) ou clonage transactionnel):
899899
1. Une version standard pour les appels classiques hors transactions.
900900
2. Un **clone transactionnel** conçu pour optimiser les transactions. Dans cette version, **chaque accès mémoire est tracé** par le compilateur (injection de barrières logicielles de lecture/écriture). Le compilateur y **élimine les barrières de transaction redondantes** et **optimise le code** de manière à ce qu'il s'exécute **le plus rapidement possible**. Cela réduit la durée globale de la transaction, limitant ainsi la probabilité qu'un autre thread écrive en même temps et provoque un avortement de transaction (*transaction abort*).
901901

0 commit comments

Comments
 (0)