Namespaces
Variants

cv ( const and volatile ) type qualifiers

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

任意の型指定子に現れ、宣言されるオブジェクトまたは命名される型のconst性やvolatile性を指定するために使用されます。これには decl-specifier-seq 宣言文法 内のもの)も含まれます。

  • const - 型が 定数 であることを定義します。
  • volatile - 型が 揮発性 であることを定義します。

目次

説明

関数型または参照型以外の(おそらく 不完全な 可能性もある)あらゆる型は、以下の4つの異なるが関連する型のグループに属する型です:

  • cv-unqualified バージョン。
  • const-qualified バージョン。
  • volatile-qualified バージョン。
  • const-volatile-qualified バージョン。

同じグループ内のこれら4つの型は、同じ representation および alignment 要件を持ちます。

配列型 は、その要素型と同じcv修飾を持つと見なされます。

constおよびvolatileオブジェクト

オブジェクトが最初に作成されるとき、使用されたcv修飾子( decl-specifier-seq の一部、または 宣言 内の declarator の一部、あるいは new-expression 内の type-id の一部)が、以下のようにオブジェクトのconst性またはvolatile性を決定します:

  • A const object
  • 型がconst修飾されたオブジェクト、または
  • constオブジェクトの非 mutable サブオブジェクト。
このようなオブジェクトは変更できません:直接変更しようとするとコンパイル時エラーとなり、間接的に変更しようとすると(例:非const型への参照またはポインタを通じてconstオブジェクトを変更する)未定義動作を引き起こします。
  • A volatile object
  • volatile修飾型のオブジェクト、
  • volatileオブジェクトの副オブジェクト、または
  • const-volatileオブジェクトの mutable 副オブジェクト。
volatile修飾型のglvalue式を通じて行われるすべてのアクセス(読み書き操作、メンバ関数呼び出しなど)は、 最適化の目的 において可視副作用として扱われる(つまり、単一の実行スレッド内では、volatileアクセスは、 シーケンス前に またはシーケンス後に順序付けられた別の可視副作用と最適化除去または並べ替えできない)。これにより、volatileオブジェクトは シグナルハンドラ との通信には適しているが、別の実行スレッドとの通信には適さない( std::memory_order を参照)。非volatile型の glvalue (例:非volatile型への参照またはポインタ)を通じてvolatileオブジェクトにアクセスしようとすると、未定義動作が発生する。
  • A const volatile object
  • const-volatile修飾された型のオブジェクト、
  • const volatileオブジェクトの非 mutable 部分オブジェクト、
  • volatileオブジェクトのconst部分オブジェクト、または
  • constオブジェクトの非 mutable volatile部分オブジェクト。
constオブジェクトとしてもvolatileオブジェクトとしても振る舞う。

各CV修飾子( const および volatile )は、いかなるCV修飾子シーケンス内でも最大1回のみ出現できます。例えば、 const const volatile const volatile は有効なCV修飾子シーケンスではありません。

mutable specifier

  • mutable - 包含オブジェクトがconstで宣言されている場合でも、mutableとして宣言されたクラスメンバの変更を許可します(つまり、クラスメンバはmutableです)。

非参照非const型の非静的 class members の宣言に現れることがあります:

class X
{
    mutable const int* p; // OK
    mutable int* const q; // 不適格
    mutable int&       r; // 不適格
};

mutable は、メンバーがクラスの外部から見える状態に影響を与えないことを指定するために使用されます(ミューテックス、メモキャッシュ、遅延評価、アクセス計装などで頻繁に使用されます)。

class ThreadsafeCounter
{
    mutable std::mutex m; // 「M&Mルール」: mutableとmutexは常に一緒に使用する
    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 を使用する必要があります。

注記

const 修飾子を非ローカルで非volatileの テンプレート (C++14以降) inline (C++17以降) 変数の宣言で使用し、かつ extern として宣言されていない場合、その変数に 内部リンケージ を与えます。これはC言語ではconstファイルスコープ変数が外部リンケージを持つ点と異なります。

C++言語の文法では mutable storage-class-specifier として扱いますが、これは型修飾子ではなく、ストレージクラスやリンケージには影響しません。

volatileの一部の使用法は非推奨となりました:

(C++20以降)

キーワード

const volatile mutable

#include <cstdlib>
int main()
{
    int n1 = 0;          // 非constオブジェクト
    const int n2 = 0;    // constオブジェクト
    int const n3 = 0;    // constオブジェクト (n2と同じ)
    volatile int n4 = 0; // volatileオブジェクト
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};        // mutableメンバを持つconstオブジェクト
    n1 = 1;   // OK: 変更可能なオブジェクト
//  n2 = 2;   // エラー: 変更不可能なオブジェクト
    n4 = 3;   // OK: 副作用として扱われる
//  x.n1 = 4; // エラー: constオブジェクトのメンバはconst
    x.n2 = 4; // OK: constオブジェクトのmutableメンバはconstではない
    const int& r1 = n1; // 非constオブジェクトにバインドされたconst参照
//  r1 = 2; // エラー: const参照を通じた変更の試み
    const_cast<int&>(r1) = 2; // OK: 非constオブジェクトn1を変更
    const int& r2 = n2; // constオブジェクトにバインドされたconst参照
//  r2 = 2; // エラー: const参照を通じた変更の試み
//  const_cast<int&>(r2) = 2; // 未定義動作: constオブジェクトn2の変更試み
    [](...){}(n3, n4, x, r2); // 参照: [[maybe_unused]]
    std::system("g++ -O3 -Wa,-adhln ./main.cpp"); // POSIXシステムではアセンブリを出力する可能性あり
}

出力例:

# 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 'const object'の定義が宣言に基づいていた オブジェクト型に基づく
CWG 1528 C++98 同じcv修飾子シーケンス内での各cv修飾子の
出現回数に関する要件がなかった
各cv修飾子は最大1回
まで
CWG 1799 C++98 mutable
const として宣言されていないデータメンバーに適用可能だったが、
メンバーの型がconst修飾されている可能性があった
const修飾された型のデータメンバーには
mutable を適用できない

関連項目

Cドキュメント for const 修飾子
Cドキュメント for volatile 修飾子
翻訳内容: - "C documentation" → "Cドキュメント" - "const qualifier" → "const修飾子"(constはC++用語のため非翻訳) - "volatile qualifier" → "volatile修飾子"(volatileはC++用語のため非翻訳) - HTMLタグ、属性、 内のコードは完全に保持 - フォーマットと構造は元のまま維持