サーチ…
前書き
記憶域クラス指定子は、宣言で使用できるキーワードです。宣言の型には影響しませんが、通常はエンティティの格納方法を変更します。
備考
auto
(C ++ 11まで)、 register
(C ++ 17まで)、 static
、 thread_local
(C ++ 11以降)、 extern
、およびextern
6つのストレージクラス指定子があります。 mutable
です。
標準によると、
多くの場合、あるstorage-class-specifierは、 指定されたdecl-specifier-seqに現れます。ただし、
thread_local
はstatic
またはextern
表示されstatic
。
宣言には、記憶域クラス指定子が含まれていない可能性があります。その場合、言語はデフォルト動作を指定します。たとえば、デフォルトでは、ブロックスコープで宣言された変数には暗黙的に自動記憶期間があります。
変更可能な
クラスの非静的な非参照データメンバーの宣言に適用できる指定子。オブジェクトがconst
あっても、クラスの可変メンバはconst
ではありません。
class C {
int x;
mutable int times_accessed;
public:
C(): x(0), times_accessed(0) {
}
int get_x() const {
++times_accessed; // ok: const member function can modify mutable data member
return x;
}
void set_x(int x) {
++times_accessed;
this->x = x;
}
};
mutable
2番目の意味はC ++ 11で追加されました。ラムダのパラメータリストをたどると、ラムダの関数呼び出し演算子の暗黙のconst
抑制されます。したがって、変更可能なラムダは、コピーによってキャプチャされたエンティティの値を変更することができます。詳細については、 可変ラムダを参照してください。
std::vector<int> my_iota(int start, int count) {
std::vector<int> result(count);
std::generate(result.begin(), result.end(),
[start]() mutable { return start++; });
return result;
}
mutable
は、変更可能なラムダを形成するためにこの方法で使用されるとき、ストレージクラス指定子ではないことに注意してください。
登録
変数が大量に使用されることをコンパイラに知らせるストレージクラス指定子。 「レジスタ」という単語は、コンパイラがCPUレジスタにそのような変数を格納して、より少ないクロックサイクルでアクセスできるようにするという事実に関連しています。 C ++ 11以降は非推奨となりました。
register int i = 0;
while (i < 100) {
f(i);
int g = i*i;
i += h(i, g);
}
局所変数と関数パラメータの両方をregister
として宣言することができます。 Cとは異なり、C ++ではregister
変数を使って何ができるかについて何ら制限はありません。たとえば、 register
変数のアドレスを取ることは有効ですが、コンパイラがそのような変数を実際にレジスタに格納するのを妨げる可能性があります。
キーワードregister
は未使用で予約済みです。キーワードregister
を使用するプログラムは不正です。
静的
static
記憶域クラス指定子には、3つの異なる意味があります。
名前空間のスコープで宣言された変数または関数への内部リンケージを提供します。
// internal function; can't be linked to static double semiperimeter(double a, double b, double c) { return (a + b + c)/2.0; } // exported to client double area(double a, double b, double c) { const double s = semiperimeter(a, b, c); return sqrt(s*(s-a)*(s-b)*(s-c)); }
変数が静的な記憶期間を持つように宣言します(
thread_local
)。名前空間スコープ変数は暗黙的に静的です。静的ローカル変数は、一度だけ初期化されます。最初のコントロールは定義を通過し、スコープが終了するたびに破棄されません。void f() { static int count = 0; std::cout << "f has been called " << ++count << " times so far\n"; }
クラスメンバーの宣言に適用すると、そのメンバーを静的メンバーとして宣言します。
struct S { static S* create() { return new S; } }; int main() { S* s = S::create(); }
クラスの静的データメンバーの場合、2と3の両方が同時に適用されることに注意してください。 static
キーワードは、メンバーを静的データメンバーにして静的記憶期間を持つ変数にします。
オート
変数の自動保存期間を設定します。自動保存期間はブロックスコープではすでにデフォルトであり、名前空間のスコープでは自動指定が許可されていないので、冗長です。
void f() {
auto int x; // equivalent to: int x;
auto y; // illegal in C++; legal in C89
}
auto int z; // illegal: namespace-scope variable cannot be automatic
C ++ 11では、 auto
は意味を完全に変更し、もはやストレージクラス指定子ではなく、代わりに型減算に使用されます。
extern
extern
ストレージクラス指定子は、コンテキストに応じて次の3つの方法のいずれかで宣言を変更できます。
それを定義することなく変数を宣言するのに使うことができます。通常、これは別の実装ファイルで定義される変数のヘッダーファイルで使用されます。
// global scope int x; // definition; x will be default-initialized extern int y; // declaration; y is defined elsewhere, most likely another TU extern int z = 42; // definition; "extern" has no effect here (compiler may warn)
それは、
const
やconstexpr
が内部リンクを持っていたとしても、名前空間スコープの変数への外部リンケージを与えます。// global scope const int w = 42; // internal linkage in C++; external linkage in C static const int x = 42; // internal linkage in both C++ and C extern const int y = 42; // external linkage in both C++ and C namespace { extern const int z = 42; // however, this has internal linkage since // it's in an unnamed namespace }
以前にリンケージで宣言されていた場合は、ブロックスコープの変数を再宣言します。それ以外の場合は、リンケージを持つ新しい変数を宣言します。これは、最も近い囲む名前空間のメンバーです。
// global scope namespace { int x = 1; struct C { int x = 2; void f() { extern int x; // redeclares namespace-scope x std::cout << x << '\n'; // therefore, this prints 1, not 2 } }; } void g() { extern int y; // y has external linkage; refers to global y defined elsewhere }
関数はextern
として宣言することもできますが、これは効果がありません。これは通常、ここで宣言された関数が別の翻訳単位で定義されていることをヒントとして使用されます。例えば:
void f(); // typically a forward declaration; f defined later in this TU
extern void g(); // typically not a forward declaration; g defined in another TU
場合は、上記のコードでは、 f
に変更されましたextern
およびg
非にextern
、それがすべてでプログラムの正しさや意味論に影響を与えないだろうが、可能性の高いコードの読者を混乱させる。