命名空間
變體
動作

cv (constvolatile) 類型限定符

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

出現在任何類型說明符中,包含聲明語法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-seqdeclarator 的一部分,或是 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) 是指:
  • 其類型為 const-volatile 限定的物件,
  • 常數易變物件的非 mutable 子物件,
  • 易變物件的 const 子物件,或
  • 常數物件的非 mutable 易變子物件。
其行為同時表現為常數物件與易變物件。

每個 cv 限定符(constvolatile)在任何 cv 限定符序列中最多只能出現一次。例如,const constvolatile 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 的用法已被棄用:

  • 作為內建遞增/遞減運算子的運算元,其類型為 volatile 的左值;
  • 作為內建直接賦值運算子的左運算元,其類型為 volatile 的左值(除非該直接賦值運算式出現在未求值語境中,或是棄值運算式);
  • 作為函數參數類型或回傳類型的 volatile 物件類型;
  • 結構化綁定聲明中的 volatile 限定符。
(自 C++20 起)

[編輯] 關鍵字

const, volatile, mutable

[編輯] 範例

#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 限定符
English Deutsch 日本語 한국어 中文(简体) 中文(繁體)