cv (const und volatile) Typqualifizierer
Erscheinen in jedem Typspezifizierer, einschließlich decl-specifier-seq von Deklarationsgrammatik, um die Konstanz oder Volatilität des zu deklarierenden Objekts oder des benannten Typs anzugeben.
- const - definiert, dass der Typ konstant ist.
- volatile - definiert, dass der Typ volatile ist.
Inhalt |
[bearbeiten] Erklärung
Jeder (möglicherweise unvollständige) Typ außer einem Funktionstyp oder Referenztyp 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 Repräsentations- und Ausrichtungsvoraussetzungen.
Array-Typen gelten als cv-qualifiziert wie ihre Elementtypen.
[bearbeiten] const und volatile Objekte
Wenn ein Objekt erstellt wird, bestimmen die verwendeten cv-Qualifizierer (die Teil von decl-specifier-seq oder Teil eines declarator in einer Deklaration oder Teil von type-id in einem new-expression sein können) die Konstanz oder Volatilität des Objekts wie folgt:
- Ein const-Objekt ist
- ein Objekt, dessen Typ const-qualifiziert ist, oder
- ein nicht-mutable-Teil eines const-Objekts.
- Ein solches Objekt kann nicht modifiziert werden: Versuche, dies direkt zu tun, sind ein Kompilierungsfehler, und Versuche, dies indirekt zu tun (z. B. durch Modifikation des const-Objekts über eine Referenz oder einen Zeiger auf einen nicht-const-Typ), führen zu undefiniertem Verhalten.
- Ein volatile-Objekt ist
- ein Objekt, dessen Typ volatile-qualifiziert ist,
- ein Teil eines volatile-Objekts, oder
- ein mutable-Teil eines const-volatile-Objekts.
- Jeder Zugriff (Lese- oder Schreibvorgang, Aufruf einer Memberfunktion usw.), der über einen glvalue-Ausdruck eines volatile-qualifizierten Typs erfolgt, wird für die Zwecke der Optimierung als sichtbarer Nebeneffekt behandelt (d. h., innerhalb eines einzelnen Ausführungsthreads können volatile-Zugriffe nicht herausoptimiert oder mit anderen sichtbaren Nebeneffekten, die sequenziert vor oder sequenziert nach dem volatile-Zugriff sind, neu geordnet werden. Dies macht volatile-Objekte geeignet für die Kommunikation mit einem Signalhandler, aber nicht mit einem anderen Ausführungsthread, siehe std::memory_order). Jeder Versuch, auf ein volatile-Objekt über einen glvalue eines nicht-volatile Typs zuzugreifen (z. B. über eine Referenz oder einen Zeiger auf einen nicht-volatile Typ), führt zu undefiniertem Verhalten.
- Ein const-volatile-Objekt ist
- Verhält sich sowohl als const-Objekt als auch als volatile-Objekt.
Jeder cv-Qualifizierer (const und volatile) kann in einer cv-Qualifizierer-Sequenz höchstens einmal vorkommen. Beispielsweise sind const const und volatile const volatile keine gültigen cv-Qualifizierer-Sequenzen.
[bearbeiten] mutable-Spezifizierer
- mutable - erlaubt die Modifikation des als mutable deklarierten Klassenmembers, auch wenn das enthaltende Objekt als const deklariert ist (d. h., der Klassenmember ist mutable).
Kann in der Deklaration eines nicht-statischen Klassenmembers eines nicht-Referenz-Nicht-Const-Typs vorkommen
class X { mutable const int* p; // OK mutable int* const q; // ill-formed mutable int& r; // ill-formed };
mutable wird verwendet, um anzugeben, dass der Member den extern sichtbaren Zustand der Klasse nicht beeinflusst (wie oft für Mutexe, Cache-Speicher, Lazy Evaluation und Zugriffs-Instrumentierung verwendet).
class ThreadsafeCounter { mutable std::mutex m; // The "M&M rule": mutable and mutex go together 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; } };
[bearbeiten] Konvertierungen
Es gibt eine partielle Ordnung der cv-Qualifizierer nach aufsteigenden Beschrä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 mehr cv-qualifizierte Typen konvertiert werden. Details finden Sie unter Qualifizierungskonvertierungen.
Um eine Referenz oder einen Zeiger auf einen cv-qualifizierten Typ in eine Referenz oder einen Zeiger auf einen weniger cv-qualifizierten Typ zu konvertieren, muss const_cast verwendet werden.
[bearbeiten] Hinweise
Der const-Qualifizierer, der in der Deklaration einer nicht-lokalen, nicht-volatile nicht-Template(seit C++14)nicht-inline(seit C++17)-Variable verwendet wird, die nicht als extern deklariert ist, verleiht ihr interne Bindung. Dies unterscheidet sich von C, wo const-Variablen auf Dateiebene externe Bindung haben.
Die C++-Sprachgrammatik behandelt mutable als Speicherklassen-Spezifizierer und nicht als Typqualifizierer, aber es beeinflusst weder die Speicherklasse noch die Bindung.
|
Einige Verwendungen von volatile sind veraltet
|
(seit C++20) |
[bearbeiten] Schlüsselwörter
[bearbeiten] Beispiel
#include <cstdlib> int main() { int n1 = 0; // non-const object const int n2 = 0; // const object int const n3 = 0; // const object (same as n2) volatile int n4 = 0; // volatile object const struct { int n1; mutable int n2; } x = {0, 0}; // const object with mutable member n1 = 1; // OK: modifiable object // n2 = 2; // error: non-modifiable object n4 = 3; // OK: treated as a side-effect // x.n1 = 4; // error: member of a const object is const x.n2 = 4; // OK: mutable member of a const object isn't const const int& r1 = n1; // reference to const bound to non-const object // r1 = 2; // error: attempt to modify through reference to const const_cast<int&>(r1) = 2; // OK: modifies non-const object n1 const int& r2 = n2; // reference to const bound to const object // r2 = 2; // error: attempt to modify through reference to const // const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2 [](...){}(n3, n4, x, r2); // see also: [[maybe_unused]] std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // may issue asm on POSIX systems }
Mögliche Ausgabe
# typical machine code produced on an x86_64 platform
# (only the code that contributes to observable side-effects is emitted)
main:
movl $0, -4(%rsp) # volatile int n4 = 0;
movl $3, -4(%rsp) # n4 = 3;
xorl %eax, %eax # return 0 (implicit)
ret[bearbeiten] Defect reports
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1428 | C++98 | die Definition von 'const-Objekt' 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 Datenmember angewendet werden, die nicht deklariert wurden const, aber die Typen der Member konnten immer noch const-qualifiziert sein |
kann mutable nicht auf Daten anwenden Member von const-qualifizierten Typen |
[bearbeiten] Siehe auch
| C-Dokumentation für const-Qualifizierer
| |
| C-Dokumentation für volatile-Qualifizierer
|