名稱空間
變體
操作

cv (constvolatile) 型別限定符

來自 cppreference.com
< cpp‎ | 語言
 
 
C++ 語言
 
 

出現在任何型別說明符中,包括宣告語法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-expressiontype-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-qualified 的物件,
  • const volatile 物件的非mutable子物件,
  • volatile 物件的 const 子物件,或
  • const 物件的非mutable volatile 子物件。
兼具 const 物件和 volatile 物件的行為。

每個 cv-限定符(constvolatile)在任何 cv-限定符序列中最多隻能出現一次。例如,const constvolatile 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 起)

[編輯] 關鍵字

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++ 標準。

缺陷報告 應用於 釋出時的行為 正確的行為
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 限定符