You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _articles/c++_attributes.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
---
2
2
layout: article
3
-
title: Attributs en C++
3
+
title: Les attributs (C++11)
4
4
permalink: articles/c++/attributes
5
5
category: c++
6
6
logo: c++.svg
@@ -23,7 +23,7 @@ En somme, il s'agit d'expliciter une intention qui **n'altère pas la logique**
23
23
24
24
## Historique
25
25
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:
27
27
28
28
-**Microsoft (MSVC)** utilise le mot-clef [``__declspec(...)``](https://learn.microsoft.com/en-us/cpp/cpp/declspec).
29
29
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é
81
81
82
82
### Positionnement dans les lambdas (Depuis C++11 / C++23)
83
83
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)):
@@ -254,7 +254,7 @@ Puisque le calcul de ``y`` nécessite la valeur de ``x``, le CPU et le compilate
254
254
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.
255
255
256
256
Imaginons le scénario d'une liste chaînée partagée entre deux threads:
257
-
{% highlight cpp %}
257
+
{% highlight cpp linenos %}
258
258
struct Node
259
259
{
260
260
int value;
@@ -332,7 +332,7 @@ Grâce à cette déclaration, le compilateur sait qu'il peut compiler l'appel de
332
332
333
333
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.
334
334
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).
336
336
337
337
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)).
338
338
@@ -811,7 +811,7 @@ En résumé: C'est la manière la plus propre de lier le retour non pas à "la f
811
811
812
812
### ``[[indeterminate]]`` (C++26)
813
813
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)**.
815
815
816
816
{% highlight cpp %}
817
817
void crashOrVulnerability()
@@ -851,7 +851,7 @@ void process()
851
851
852
852
> 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.
853
853
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)**.
855
855
856
856
### ``[[optimize_for_synchronized]]`` (TM TS)
857
857
@@ -861,7 +861,7 @@ La mémoire transactionnelle permet d'exécuter des blocs de code de manière at
861
861
862
862
#### Le mot clef experimental ``synchronized``
863
863
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).
865
865
866
866
{% highlight cpp %}
867
867
void process(int value)
@@ -880,7 +880,7 @@ Lorsqu'un bloc ``synchronized`` appelle une fonction **non [inlinée](https://fr
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.
884
884
885
885
{% highlight cpp %}
886
886
// Indique au compilateur d'optimiser cette fonction pour l'appel transactionnel
@@ -895,7 +895,7 @@ void process()
895
895
}
896
896
{% endhighlight %}
897
897
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):
899
899
1. Une version standard pour les appels classiques hors transactions.
900
900
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*).
0 commit comments