1. ホーム
  2. c++

[解決済み】C++におけるstaticキーワードとその様々な使用法

2022-04-06 10:25:07

質問

キーワード static C++ではいくつかの意味があり、私は非常に混乱し、実際にどのように動作することになっているのか、自分の考えを曲げることができません。

私が理解したところでは static ストレージの持続時間、つまりグローバルの場合はプログラムの寿命まで続きますが、ローカルの場合はデフォルトでゼロ初期化されているということですね。

C++規格では、クラスのデータメンバに対して、このようにキーワード static :

3.7.1 静的記憶期間[basic.stc.static]について

3 static キーワードは、静的な保存期間を持つローカル変数を宣言するために使用することができます。

4 クラス定義でクラスデータメンバーに適用されるキーワードstaticは、データメンバーに静的な保存期間を与えます。

とはどういう意味なのでしょうか? ローカル変数 ? それは関数ローカル変数ですか?というのも、関数ローカルを宣言するときに static は、この関数に初めて入ったときに一度だけ初期化されるということです。

また、ストレージの持続時間はクラスのメンバーに関してのみ語られており、インスタンスに依存しないことはどうなのか、それはまた static ないのか?それとも保管期間?

では static とファイルスコープを設定できますか?すべてのグローバル変数は、デフォルトで静的な保存期間を持つとみなされるのでしょうか?以下(3.7.1項)は、そうであることを示しているようです。

1 動的ストレージ期間を持たないすべての変数、スレッドストレージ期間を持たないすべての変数、および ローカルではない は静的記憶期間を持つ。これらの実体の保存期間は,プログラムの継続期間とする(3.6.2,3.6.3)。

どのように static は、変数の連結に関係するのでしょうか?

この全体の static キーワードは実に紛らわしいのですが、どなたかこのキーワードのさまざまな使い方を明らかにしていただけないでしょうか。 いつ を初期化するために static のクラス・メンバーですか?

解決方法は?

変数

static 変数が存在します。 で定義されている翻訳ユニットです。 とする。

  • 名前空間スコープにある場合(つまり関数やクラスの外にある場合)、他の翻訳ユニットからアクセスすることはできません。 これは、内部リンクまたは静的保存期間として知られています。 constexpr . それ以外の場合は、各翻訳ユニットで別々の変数が使用されることになり、非常に紛らわしいです)
  • 変数の場合 関数内 他のローカル変数と同じように、関数の外からアクセスすることはできません。(これが彼らの言うローカルです)
  • のため、クラスメンバはスコープを制限されない。 static しかし、インスタンスと同様にクラスからアドレス指定することができます(たとえば std::string::npos ). [注意 宣言 クラス内の静的メンバは、通常はまだ 定義 翻訳単位(cppファイル)で、1クラスにつき1つだけです] 。

の場所をコードとして表示します。

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

翻訳ユニット内の関数が実行される前(場合によっては main を実行し始めると、その翻訳ユニット内の静的な保存期間(名前空間スコープ)を持つ変数が "定数初期化"されます(quotは constexpr を使用し、非ローカルは適切に"動的初期化"されます。 翻訳ユニットで定義された順番に (のようなものに対して)。 std::string="HI"; でない場合は constexpr ). 最後に、関数ローカルの静的要素は、それが宣言されている行に初めて実行が到達したときに初期化されます。 すべて static 変数はすべて初期化の逆の順序で破壊されます。

このようなことを正しく理解するための最も簡単な方法は、すべての静的変数が constexpr を関数スタティックローカルに初期化することで、 どんな場合でもスタティックやグローバルが適切に初期化されるようにし、 その結果として 静的初期化順序の大失敗 .

T& get_global() {
    static T global = initial_value();
    return global;
}

名前空間スコープ変数がデフォルトで "static storage duration" を持つという仕様は、翻訳ユニットの有効期間" ビットを意味するので、注意が必要です。 ではなく は、ファイルの外からアクセスできないことを意味します。

機能一覧

大幅にわかりやすくなりました。 static は、クラスのメンバ関数として使われることが多く、独立した関数として使われることはごくまれです。

スタティック・メンバー関数は、通常のメンバー関数と異なり、クラスのインスタンスがなくても呼び出すことができ、インスタンスがないため、クラスの非スタティック・メンバーにアクセスすることができません。 静的変数は、あるクラスに対して、インスタンスのメンバを絶対に参照しない関数を用意したい場合、あるいは static メンバ変数

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

A static free-functionは、その関数が他の翻訳ユニットで参照されないことを意味し、したがってリンカはその関数を完全に無視することができます。 これにはわずかながら目的があります。

  • cppファイルで使用することにより、その関数が他のファイルから決して使用されないことを保証することができます。
  • ヘッダーに置くと、すべてのファイルがその関数のコピーを持つことになります。 インラインでもほとんど同じことができるので、有用ではありません。
  • 作業軽減によるリンク時間の短縮
  • 各翻訳ユニットには、同じ名前の関数を置くことができ、それらはすべて異なることを行うことができます。 例えば static void log(const char*) {} をそれぞれの cpp ファイルに配置し、それぞれ異なる方法でログを記録することができます。