cv (const
和 volatile
) 型別限定符
出現在任何型別說明符中,包括宣告語法的 decl-specifier-seq 中,以指定所宣告物件或所命名型別的 constness 或 volatility。
- const - 定義型別是 *常量*。
- volatile - 定義型別是 *易變* 的。
目錄 |
[編輯] 解釋
除了函式型別或引用型別之外的任何(可能是不完整的)型別都屬於以下四種不同但相關的型別組:
- 一個 *cv-unqualified* 版本。
- 一個 *const-qualified* 版本。
- 一個 *volatile-qualified* 版本。
- 一個 *const-volatile-qualified* 版本。
陣列型別被認為具有與其元素型別相同的 cv-限定。
[編輯] const 和 volatile 物件
當一個物件首次建立時,所使用的 cv-限定符(可以是宣告中 decl-specifier-seq 的一部分或 declarator 的一部分,或new-expression中 type-id 的一部分)決定了物件的 constness 或 volatility,如下所示:
- 一個 *const 物件* 是
- 型別為 const-qualified 的物件,或
- const 物件的非mutable子物件。
- 這樣的物件不能被修改:直接修改會是一個編譯時錯誤,間接修改(例如,透過非 const 型別的引用或指標修改 const 物件)會導致未定義行為。
- 一個 *volatile 物件* 是
- 型別為 volatile-qualified 的物件,
- volatile 物件的子物件,或
- const-volatile 物件的mutable子物件。
- 透過 volatile-qualified 型別 glvalue 表示式進行的每次訪問(讀寫操作、成員函式呼叫等)都被視為最佳化目的的可見副作用(即,在單個執行執行緒中,volatile 訪問不能被最佳化掉,也不能與在 volatile 訪問之前或之後定序的另一個可見副作用重新排序。這使得 volatile 物件適用於與訊號處理程式通訊,但不適用於與另一個執行執行緒通訊,請參閱std::memory_order)。任何透過非 volatile 型別的glvalue(例如,透過非 volatile 型別的引用或指標)訪問 volatile 物件的嘗試都會導致未定義行為。
- 一個 *const volatile 物件* 是
- 兼具 const 物件和 volatile 物件的行為。
每個 cv-限定符(const 和 volatile)在任何 cv-限定符序列中最多隻能出現一次。例如,const const 和 volatile const volatile 不是有效的 cv-限定符序列。
[編輯] mutable
說明符
- mutable - 允許修改宣告為 mutable 的類成員,即使包含物件宣告為 const(即,類成員是可變的)。
可以出現在非引用非 const 型別的非靜態類成員的宣告中
class X { mutable const int* p; // OK mutable int* const q; // ill-formed mutable int& r; // ill-formed };
mutable 用於指定成員不影響類的外部可見狀態(通常用於互斥鎖、備忘快取、延遲評估和訪問檢測)。
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; } };
[編輯] 轉換
cv-限定符根據限制增加的順序存在部分排序。型別可以被稱為 *更* 或 *更少* cv-限定的:
- unqualified < const
- unqualified < volatile
- unqualified < const volatile
- const < const volatile
- volatile < const volatile
指向 cv-qualified 型別的引用和指標可以隱式轉換為指向更 cv-qualified 型別的引用和指標,詳見限定符轉換。
要將指向 cv-qualified 型別的引用或指標轉換為指向較少 cv-qualified 型別的引用或指標,必須使用const_cast
。
[編輯] 注意
在非區域性非 volatile 非模板(C++14 起)非inline(C++17 起) 變數的宣告中使用 const 限定符,如果該變數未宣告為 extern,則它具有內部連結。這與 C 不同,C 中 const 檔案作用域變數具有外部連結。
C++ 語言語法將 mutable 視為儲存類說明符,而不是型別限定符,但它不影響儲存類或連結。
某些 volatile 的用法已被棄用 |
(C++20 起) |
[編輯] 關鍵字
[編輯] 示例
#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 }
可能的輸出
# 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
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 1428 | C++98 | “const 物件”的定義基於宣告 | 基於物件型別 |
CWG 1528 | C++98 | 對同一 cv-限定符序列中每個 cv-限定符的出現次數沒有要求 對同一 cv-限定符序列中每個 cv-限定符的出現次數沒有要求 |
最多一次 每個 cv-限定符 |
CWG 1799 | C++98 | mutable 可以應用於未宣告為 const 的資料成員 const,但成員型別仍可以是 const-qualified |
不能將 mutable 應用於 const-qualified 型別的資料成員 const-qualified 型別的資料成員 |
[編輯] 另見
C 文件 關於 const 限定符
| |
C 文件 關於 volatile 限定符
|