cv
(
const
and
volatile
)
type qualifiers
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
- 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
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
|