Namespaces
Variants

cv ( const and volatile ) type qualifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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
  • un objet dont le type est qualifié const-volatile,
  • un sous-objet non- mutable d'un objet const volatile,
  • un sous-objet const d'un objet volatile, ou
  • un sous-objet volatile non- mutable d'un objet const.
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

const , volatile , mutable

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