cv (const および volatile) 型修飾子
宣言されるオブジェクト、または名前を付けられる型の constness または volatility を指定するために、宣言文法の decl-specifier-seq を含む任意の型指定子に現れます。
- const - 型が定数であることを定義します。
- volatile - 型が揮発性であることを定義します。
目次 |
[編集] 説明
関数型または参照型以外の任意の(おそらく不完全な)型は、以下の4つの異なるが関連する型のグループに属する型です。
- cv-unqualified バージョン。
- const-qualified バージョン。
- volatile-qualified バージョン。
- const-volatile-qualified バージョン。
同じグループ内のこれらの4つの型は、同じ表現とアライメント要件を持ちます。
配列型は、その要素型と同じcv修飾を持つとみなされます。
[編集] const および volatile オブジェクト
オブジェクトが最初に作成されるとき、使用されるcv修飾子(宣言のdecl-specifier-seqの一部、またはdeclaratorの一部、あるいはnew-expressionのtype-idの一部である可能性があります)は、以下のようにオブジェクトのconstnessまたはvolatilityを決定します。
- const オブジェクトとは、
- 型がconst修飾されているオブジェクト、または
- const オブジェクトの非mutableなサブオブジェクト。
- このようなオブジェクトは変更できません。直接変更しようとするとコンパイル時エラーとなり、間接的に変更しようとすると(例えば、非const型への参照やポインタを介してconstオブジェクトを変更するなど)未定義の動作となります。
- volatile オブジェクトとは、
- 型がvolatile修飾されているオブジェクト、
- volatile オブジェクトのサブオブジェクト、または
- const-volatile オブジェクトのmutableなサブオブジェクト。
- volatile修飾された型のglvalue式を介して行われるすべてのアクセス(読み取りまたは書き込み操作、メンバ関数呼び出しなど)は、最適化の目的において可視な副作用として扱われます(つまり、単一のスレッド内では、volatileアクセスは最適化されたり、volatileアクセスのシーケンスの前または後に別の可視な副作用と並べ替えられたりすることはありません。これにより、volatileオブジェクトはシグナルハンドラとの通信には適していますが、他のスレッドとの通信には適していません。std::memory_orderを参照)。非volatile型のglvalue(例:非volatile型への参照またはポインタを介して)を介してvolatileオブジェクトにアクセスしようとすると、未定義の動作となります。
- const volatile オブジェクトとは、
- const オブジェクトおよび volatile オブジェクトの両方として動作します。
各cv修飾子(const および volatile)は、任意のcv修飾子シーケンス内に最大1回しか現れません。例えば、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修飾がされていると言えます。
- unqualified < const
- unqualified < volatile
- unqualified < const volatile
- const < const volatile
- volatile < const volatile
cv修飾された型への参照とポインタは、よりcv修飾された型への参照とポインタに暗黙的に変換できます。詳細については、資格変換を参照してください。
cv修飾された型への参照またはポインタを、より少ないcv修飾された型への参照またはポインタに変換するには、const_castを使用する必要があります。
[編集] 注釈
非ローカル非揮発性非テンプレート(C++14以降)非インライン(C++17以降)変数(extern と宣言されていないもの)の宣言で使われる const 修飾子は、その変数に内部リンケージを与えます。これは、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++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 1428 | C++98 | 'const オブジェクト' の定義は宣言に基づいていた | オブジェクト型に基づく |
| CWG 1528 | C++98 | 出現回数に関する要件がなかった 同じcv修飾子シーケンス内の各cv修飾子について |
最大1回 各cv修飾子について |
| CWG 1799 | C++98 | mutable は宣言されていないデータメンバーに適用できた const、しかしそのメンバーの型は依然としてconst修飾されているかもしれない |
mutable をデータに適用できない const修飾された型のメンバー |
[編集] 関連項目
| C ドキュメント const 修飾子について
| |
| C ドキュメント volatile 修飾子について
|