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

Erscheinen in jedem Typbezeichner, einschließlich decl-specifier-seq der Deklarationsgrammatik , um die Konstanz oder Volatilität des deklarierten Objekts oder des benannten Typs zu spezifizieren.

  • const - definiert, dass der Typ konstant ist.
  • volatile - definiert, dass der Typ flüchtig ist.

Inhaltsverzeichnis

Erklärung

Jeder (möglicherweise unvollständige ) Typ außer function type oder reference type ist ein Typ in einer Gruppe der folgenden vier unterschiedlichen aber verwandten Typen:

  • Eine cv-unqualifizierte Version.
  • Eine const-qualifizierte Version.
  • Eine volatile-qualifizierte Version.
  • Eine const-volatile-qualifizierte Version.

Diese vier Typen in derselben Gruppe haben dieselben representation und alignment Anforderungen.

Array-Typen werden als mit derselben CV-Qualifikation wie ihre Elementtypen versehen betrachtet.

const- und volatile-Objekte

Wenn ein Objekt erstmals erstellt wird, bestimmen die verwendeten cv-Qualifizierer (die Teil des decl-specifier-seq oder Teil eines declarator in einer Deklaration sein können, oder Teil des type-id in einem new-expression ) die Konstanz oder Volatilität des Objekts wie folgt:

  • Ein const object ist
  • ein Objekt, dessen Typ const-qualifiziert ist, oder
  • ein nicht- mutable Unterobjekt eines const-Objekts.
Ein solches Objekt kann nicht modifiziert werden: Der Versuch, dies direkt zu tun, ist ein Compile-Time-Fehler, und der Versuch, dies indirekt zu tun (z.B. durch Modifikation des const-Objekts über eine Referenz oder einen Zeiger auf einen nicht-const-Typ) führt zu undefiniertem Verhalten.
  • Ein volatile object ist
  • ein Objekt, dessen Typ volatile-qualifiziert ist,
  • ein Unterobjekt eines volatile-Objekts, oder
  • ein mutable Unterobjekt eines const-volatile-Objekts.
Jeder Zugriff (Lese- oder Schreiboperation, Memberfunktionsaufruf etc.), der durch einen glvalue-Ausdruck vom volatile-qualifizierten Typ erfolgt, wird als sichtbarer Seiteneffekt für die Zwecke der Optimierung behandelt (d.h. innerhalb eines einzelnen Ausführungsstrangs können volatile-Zugriffe nicht wegoptimiert oder mit einem anderen sichtbaren Seiteneffekt, der sequenced-before oder sequenced-after dem volatile-Zugriff ist, neu angeordnet werden). Dies macht volatile-Objekte geeignet für die Kommunikation mit einem Signal-Handler , aber nicht mit einem anderen Ausführungsstrang, siehe std::memory_order ). Jeder Versuch, auf ein volatile-Objekt durch einen glvalue eines nicht-volatile-Typs zuzugreifen (z.B. durch eine Referenz oder einen Zeiger auf einen nicht-volatile-Typ), führt zu undefiniertem Verhalten.
  • Ein const volatile object ist
  • ein Objekt, dessen Typ const-volatile-qualifiziert ist,
  • ein nicht- mutable Unterobjekt eines const volatile Objekts,
  • ein const Unterobjekt eines volatile Objekts, oder
  • ein nicht- mutable volatile Unterobjekt eines const Objekts.
Verhält sich sowohl als ein const Objekt als auch als ein volatile Objekt.

Jeder cv-Qualifizierer ( const und volatile ) kann höchstens einmal in jeder cv-Qualifizierer-Sequenz vorkommen. Zum Beispiel sind const const und volatile const volatile keine gültigen cv-Qualifizierer-Sequenzen.

mutable Spezifizierer

  • mutable - erlaubt die Modifikation des als mutable deklarierten Klassenmembers, selbst wenn das enthaltende Objekt als const deklariert ist (d.h., der Klassenmember ist veränderlich).

Kann in der Deklaration eines nicht-statischen Klassenmembers vom nicht-Referenz nicht-const Typ auftreten:

class X
{
    mutable const int* p; // OK
    mutable int* const q; // ungültig
    mutable int&       r; // ungültig
};

mutable wird verwendet, um anzugeben, dass das Mitglied den extern sichtbaren Zustand der Klasse nicht beeinflusst (wie häufig bei Mutexen, Memo-Caches, Lazy Evaluation und Zugriffsinstrumentierung verwendet).

class ThreadsafeCounter
{
    mutable std::mutex m; // Die "M&M-Regel": mutable und mutex gehören zusammen
    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;
    }
};

Konvertierungen

Es gibt eine partielle Ordnung von CV-Qualifizierern nach der Reihenfolge zunehmender Einschränkungen. Der Typ kann als mehr oder weniger CV-qualifiziert bezeichnet werden als:

  • unqualifiziert < const
  • unqualifiziert < volatile
  • unqualifiziert < const volatile
  • const < const volatile
  • volatile < const volatile

Referenzen und Zeiger auf cv-qualifizierte Typen können implizit in Referenzen und Zeiger auf stärker cv-qualifizierte Typen konvertiert werden, siehe qualification conversions für Details.

Um eine Referenz oder einen Zeiger auf einen cv-qualifizierten Typ in eine Referenz oder einen Zeiger auf einen weniger cv-qualifizierten Typ umzuwandeln, const_cast muss verwendet werden.

Hinweise

Der const Qualifizierer, der bei der Deklaration einer nicht-lokalen, nicht-flüchtigen Nicht- Template (seit C++14) Nicht- Inline (seit C++17) Variable, die nicht als extern deklariert ist, verleiht ihr eine interne Bindung . Dies unterscheidet sich von C, wo const Dateibereichsvariablen eine externe Bindung haben.

Die C++-Sprachgrammatik behandelt mutable als einen storage-class-specifier , anstatt als einen Typqualifizierer, aber es beeinflusst weder Speicherklasse noch Linkage.

Einige Verwendungen von volatile sind veraltet:

(since C++20)

Schlüsselwörter

const , volatile , mutable

Beispiel

#include <cstdlib>
int main()
{
    int n1 = 0;          // nicht-konstantes Objekt
    const int n2 = 0;    // konstantes Objekt
    int const n3 = 0;    // konstantes Objekt (gleich wie n2)
    volatile int n4 = 0; // volatiles Objekt
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // konstantes Objekt mit mutable-Member
    n1 = 1;   // OK: modifizierbares Objekt
//  n2 = 2;   // Fehler: nicht modifizierbares Objekt
    n4 = 3;   // OK: wird als Seiteneffekt behandelt
//  x.n1 = 4; // Fehler: Member eines konstanten Objekts ist const
    x.n2 = 4; // OK: mutable-Member eines konstanten Objekts ist nicht const
    const int& r1 = n1; // Referenz auf const gebunden an nicht-konstantes Objekt
//  r1 = 2; // Fehler: Versuch der Modifikation durch Referenz auf const
    const_cast<int&>(r1) = 2; // OK: modifiziert nicht-konstantes Objekt n1
    const int& r2 = n2; // Referenz auf const gebunden an konstantes Objekt
//  r2 = 2; // Fehler: Versuch der Modifikation durch Referenz auf const
//  const_cast<int&>(r2) = 2; // undefiniertes Verhalten: Versuch der Modifikation eines konstanten Objekts n2
    [](...){}(n3, n4, x, r2); // siehe auch: [[maybe_unused]]
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // kann Assembler auf POSIX-Systemen ausgeben
}

Mögliche Ausgabe:

# typischer Maschinencode auf einer x86_64-Plattform
# (nur der Code, der zu beobachtbaren Seiteneffekten beiträgt, wird ausgegeben)
main:
    movl    $0, -4(%rsp) # volatile int n4 = 0;
    movl    $3, -4(%rsp) # n4 = 3;
    xorl    %eax, %eax   # return 0 (implizit)
    ret

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 1428 C++98 die Definition von 'const object' basierte auf der Deklaration basierend auf dem Objekttyp
CWG 1528 C++98 es gab keine Anforderung an die Anzahl der Vorkommen
jedes cv-Qualifizierers in derselben cv-Qualifizierer-Sequenz
höchstens einmal für
jeden cv-Qualifizierer
CWG 1799 C++98 mutable konnte auf Datenelemente angewendet werden, die nicht
const deklariert waren, aber die Typen der Elemente könnten dennoch const-qualifiziert sein
kann mutable nicht auf Datenelemente
von const-qualifizierten Typen anwenden

Siehe auch

C-Dokumentation für const Qualifizierer
C-Dokumentation für volatile Qualifizierer