cv (const 與 volatile) 類型限定符
出現在任何類型說明符中,包含聲明語法的 decl-specifier-seq(聲明說明符序列),用於指定所聲明物件或所命名類型的 const 性(常數性)或 volatile 性(易變性)。
- const - 定義該類型為常數 (constant)。
- volatile - 定義該類型為易變 (volatile)。
目錄 |
[編輯] 說明
除 函數類型 或 參考類型 外,任何(可能為不完整的)類型都屬於以下四種不同但相關的類型組之一
- 無 cv 限定的 (cv-unqualified) 版本。
- const 限定的 (const-qualified) 版本。
- volatile 限定的 (volatile-qualified) 版本。
- const-volatile 限定的 (const-volatile-qualified) 版本。
陣列類型被視為與其元素類型具有相同的 cv 限定性。
[編輯] const 與 volatile 物件
當物件首次建立時,所使用的 cv 限定符(可能是聲明中 decl-specifier-seq 或 declarator 的一部分,或是 new 運算式中 type-id 的一部分)會決定該物件的 const 性或 volatile 性,如下所示:
- 所謂的常數物件 (const object) 是指:
- 其類型為 const 限定的物件,或
- 常數物件的非 mutable 子物件。
- 此類物件無法被修改:直接嘗試修改是編譯期錯誤,而間接修改(例如透過指向非 const 類型的參考或指標來修改 const 物件)則會導致未定義行為。
- 所謂的易變物件 (volatile object) 是指:
- 其類型為 volatile 限定的物件,
- 易變物件的子物件,或
- const-volatile 物件的 mutable 子物件。
- 透過 volatile 限定類型的 glvalue 運算式進行的每一次存取(讀取或寫入操作、成員函數呼叫等)都被視為一種可見的副作用,以用於最佳化目的(即在單一執行緒中,volatile 存取不能被最佳化掉,也不能與其他定序於 (sequenced-before) 該 volatile 存取之前或之後的可見副作用進行重新排序)。這使得 volatile 物件適用於與 訊號處理常式 進行通訊,但不適用於與另一個執行緒進行通訊,參閱 std::memory_order)。任何透過非 volatile 類型的 glvalue(例如透過指向非 volatile 類型的參考或指標)存取 volatile 物件的嘗試,都會導致未定義行為。
- 所謂的常數易變物件 (const volatile object) 是指:
- 其行為同時表現為常數物件與易變物件。
每個 cv 限定符(const 與 volatile)在任何 cv 限定符序列中最多只能出現一次。例如,const const 和 volatile const volatile 皆非有效的 cv 限定符序列。
[編輯] mutable 說明符
- mutable - 即使包含它的物件被聲明為 const,也允許修改被聲明為 mutable 的類別成員(即該類別成員是可變的)。
可出現於非參考、非 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 限定性:
- 無限定 < const
- 無限定 < volatile
- 無限定 < const volatile
- const < const volatile
- volatile < const volatile
指向 cv 限定類型的參考與指標可以隱式轉換為指向更多 cv 限定類型的參考與指標,詳情請參閱限定轉換。
若要將指向 cv 限定類型的參考或指標轉換為指向較少 cv 限定類型的參考或指標,必須使用 const_cast。
[編輯] 附註
用於非區域性、非 volatile 非範本(C++14 起)非內聯(C++17 起)變數聲明中的 const 限定符(且未聲明為 extern),會給予其內部連結。這與 C 語言不同,C 語言中檔案作用域的 const 變數具有外部連結。
C++ 語言語法將 mutable 視為 儲存類別說明符 (storage-class-specifier),而非類型限定符,但它不會影響儲存類別或連結。
|
某些 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++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 1428 | C++98 | '常數物件' 的定義基於聲明 | 基於物件類型 |
| CWG 1528 | C++98 | 對同一 cv 限定符序列中每個 cv 限定符 出現次數沒有要求 |
對於每個 cv 限定符 最多出現一次 |
| CWG 1799 | C++98 | mutable 可應用於未聲明為 const 的資料成員,但這些成員的類型可能仍是 const 限定的 |
不能將 mutable 應用於 const 限定類型的資料成員 |
[編輯] 參閱
| C 文件 關於 const 限定符
| |
| C 文件 關於 volatile 限定符
|