サーチ…


前書き

記憶域クラス指定子は、宣言で使用できるキーワードです。宣言の型には影響しませんが、通常はエンティティの格納方法を変更します。

備考

auto (C ++ 11まで)、 register (C ++ 17まで)、 staticthread_local (C ++ 11以降)、 extern 、およびextern 6つのストレージクラス指定子があります。 mutableです。

標準によると、

多くの場合、あるstorage-class-specifierは、 指定されたdecl-specifier-seqに現れます。ただし、 thread_localstaticまたは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;
    }
};
C ++ 11

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は、変更可能なラムダを形成するためにこの方法で使用されるとき、ストレージクラス指定子ではないことに注意してください。

登録

C ++ 17

変数が大量に使用されることをコンパイラに知らせるストレージクラス指定子。 「レジスタ」という単語は、コンパイラが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変数のアドレスを取ることは有効ですが、コンパイラがそのような変数を実際にレジスタに格納するのを妨げる可能性があります。

C ++ 17

キーワードregisterは未使用で予約済みです。キーワードregisterを使用するプログラムは不正です。

静的

static記憶域クラス指定子には、3つの異なる意味があります。

  1. 名前空間のスコープで宣言された変数または関数への内部リンケージを提供します。

    // 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));
    }
    
  2. 変数が静的な記憶期間を持つように宣言します( thread_local )。名前空間スコープ変数は暗黙的に静的です。静的ローカル変数は、一度だけ初期化されます。最初のコントロールは定義を通過し、スコープが終了するたびに破棄されません。

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. クラスメンバーの宣言に適用すると、そのメンバーを静的メンバーとして宣言します。

    struct S {
        static S* create() {
            return new S;
        }
    };
    int main() {
        S* s = S::create();
    }
    

クラスの静的データメンバーの場合、2と3の両方が同時に適用されることに注意してください。 staticキーワードは、メンバーを静的データメンバーにして静的記憶期間を持つ変数にします。

オート

C ++ 03

変数の自動保存期間を設定します。自動保存期間はブロックスコープではすでにデフォルトであり、名前空間のスコープでは自動指定が許可されていないので、冗長です。

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つの方法のいずれかで宣言を変更できます。

  1. それを定義することなく変数を宣言するのに使うことができます。通常、これは別の実装ファイルで定義される変数のヘッダーファイルで使用されます。

    // 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)
    
  2. それは、 constconstexprが内部リンクを持っていたとしても、名前空間スコープの変数への外部リンケージを与えます。

    // 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
    }
    
  3. 以前にリンケージで宣言されていた場合は、ブロックスコープの変数を再宣言します。それ以外の場合は、リンケージを持つ新しい変数を宣言します。これは、最も近い囲む名前空間のメンバーです。

    // 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 、それがすべてでプログラムの正しさや意味論に影響を与えないだろうが、可能性の高いコードの読者を混乱させる。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow