cv
(
const
and
volatile
)
type qualifiers
Apparaît dans tout spécificateur de type, y compris decl-specifier-seq de la grammaire de déclaration , pour spécifier la constance ou la volatilité de l'objet déclaré ou du type nommé.
- const - définit que le type est constant .
- volatile - définit que le type est volatile .
Table des matières |
Explication
Tout type (éventuellement incomplet ) autre que function type ou reference type est un type appartenant à l'un des quatre types distincts mais apparentés suivants :
- Une version non qualifiée cv .
- Une version qualifiée const .
- Une version qualifiée volatile .
- Une version qualifiée const-volatile .
Ces quatre types du même groupe ont les mêmes exigences de représentation et d'alignement .
Types de tableau sont considérés comme ayant la même qualification cv que leurs types d'éléments.
Objets const et volatile
Lorsqu'un objet est créé pour la première fois, les qualificateurs cv utilisés (qui peuvent faire partie de decl-specifier-seq ou partie d'un declarator dans une déclaration , ou partie de type-id dans une new-expression ) déterminent la constance ou la volatilité de l'objet, comme suit :
- Un objet const est
-
- un objet dont le type est qualifié const, ou
- un sous-objet non- mutable d'un objet const.
- Un tel objet ne peut pas être modifié : toute tentative de le faire directement est une erreur de compilation, et toute tentative indirecte (par exemple, en modifiant l'objet const via une référence ou un pointeur vers un type non-const) entraîne un comportement indéfini.
- Un objet volatile est
-
- un objet dont le type est qualifié volatile,
- un sous-objet d'un objet volatile, ou
- un sous-objet mutable d'un objet const-volatile.
- Chaque accès (opération de lecture ou d'écriture, appel de fonction membre, etc.) effectué via une expression glvalue de type qualifié volatile est traité comme un effet secondaire visible pour les besoins d'optimisation (c'est-à-dire, dans un seul thread d'exécution, les accès volatiles ne peuvent pas être optimisés ou réordonnés avec un autre effet secondaire visible qui est séquencé-avant ou séquencé-après l'accès volatile. Cela rend les objets volatiles adaptés à la communication avec un gestionnaire de signal , mais pas avec un autre thread d'exécution, voir std::memory_order ). Toute tentative d'accéder à un objet volatile via une glvalue de type non-volatile (par exemple via une référence ou un pointeur vers un type non-volatile) entraîne un comportement indéfini.
- Un objet const volatile est
- Se comporte à la fois comme un objet const et comme un objet volatile.
Chaque qualificatif cv ( const et volatile ) peut apparaître au maximum une fois dans toute séquence de qualificatifs cv. Par exemple, const const et volatile const volatile ne sont pas des séquences de qualificatifs cv valides.
mutable
spécificateur
- mutable - permet la modification du membre de classe déclaré mutable même si l'objet contenant est déclaré const (c'est-à-dire que le membre de classe est mutable).
Peut apparaître dans la déclaration d'un membre de classe non statique de type non référence non const :
class X { mutable const int* p; // OK mutable int* const q; // incorrect mutable int& r; // incorrect };
mutable est utilisé pour spécifier que le membre n'affecte pas l'état visible extérieurement de la classe (comme souvent utilisé pour les mutex, les caches mémo, l'évaluation paresseuse et l'instrumentation d'accès).
class ThreadsafeCounter { mutable std::mutex m; // Règle "M&M" : mutable et mutex vont ensemble int data = 0; public: int get() const { std::lock_guard<std::mutex> lk(m); return data; } void inc() { std::lock_guard<std::mutex> lk(m); ++data; } };
Conversions
Il existe un ordre partiel des qualificateurs cv selon l'ordre des restrictions croissantes. Le type peut être dit plus ou moins qualifié cv que :
- non qualifié < const
- non qualifié < volatile
- non qualifié < const volatile
- const < const volatile
- volatile < const volatile
Les références et les pointeurs vers des types qualifiés cv peuvent être implicitement convertis en références et pointeurs vers des types plus qualifiés cv. Consultez les conversions de qualification pour plus de détails.
Pour convertir une référence ou un pointeur vers un type qualifié cv en une référence ou un pointeur vers un type moins qualifié cv,
const_cast
doit être utilisé.
Notes
Le qualificateur const utilisé dans une déclaration d'une variable non-locale non-volatile non- template (depuis C++14) non- inline (depuis C++17) qui n'est pas déclarée extern lui confère une liaison interne . Ceci diffère du C où les variables const de portée fichier ont une liaison externe.
La grammaire du langage C++ traite mutable comme un storage-class-specifier , plutôt qu'un qualificateur de type, mais cela n'affecte ni la classe de stockage ni la liaison.
|
Certaines utilisations de volatile sont dépréciées :
|
(depuis C++20) |
Mots-clés
Exemple
#include <cstdlib> int main() { int n1 = 0; // objet non-const const int n2 = 0; // objet const int const n3 = 0; // objet const (identique à n2) volatile int n4 = 0; // objet volatile const struct { int n1; mutable int n2; } x = {0, 0}; // objet const avec membre mutable n1 = 1; // OK : objet modifiable // n2 = 2; // erreur : objet non modifiable n4 = 3; // OK : traité comme un effet secondaire // x.n1 = 4; // erreur : membre d'un objet const est const x.n2 = 4; // OK : membre mutable d'un objet const n'est pas const const int& r1 = n1; // référence vers const liée à un objet non-const // r1 = 2; // erreur : tentative de modification via référence vers const const_cast<int&>(r1) = 2; // OK : modifie l'objet non-const n1 const int& r2 = n2; // référence vers const liée à un objet const // r2 = 2; // erreur : tentative de modification via référence vers const // const_cast<int&>(r2) = 2; // comportement indéfini : tentative de modification d'un objet const n2 [](...){}(n3, n4, x, r2); // voir aussi : [[maybe_unused]] std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // peut produire de l'assembleur sur les systèmes POSIX }
Sortie possible :
# code machine typique produit sur une plateforme x86_64
# (seul le code contribuant aux effets secondaires observables est émis)
main:
movl $0, -4(%rsp) # volatile int n4 = 0;
movl $3, -4(%rsp) # n4 = 3;
xorl %eax, %eax # return 0 (implicite)
ret
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 1428 | C++98 | la définition d'« objet const » était basée sur la déclaration | basée sur le type d'objet |
| CWG 1528 | C++98 |
aucune exigence sur le nombre d'occurrences
de chaque qualificatif cv dans la même séquence de qualificatifs cv |
au plus une fois pour
chaque qualificatif cv |
| CWG 1799 | C++98 |
mutable
pouvait être appliqué aux membres de données non déclarés
const , mais les types des membres pouvaient toujours être qualifiés const |
ne peut pas appliquer
mutable
aux membres de
données de types qualifiés const |
Voir aussi
|
Documentation C
pour
const
qualificateur
|
|
|
Documentation C
pour
volatile
qualificateur
|