14

Test::というクラスがある場合

class Test
{
    static std::vector<int> staticVector;
};

staticVectorはいつ構築され、いつ破棄されますか?

Testクラスの最初のオブジェクトのインスタンス化によるものですか、それとも通常の静的変数のようなものですか?

明確にするために、この質問はプログラミング言語の概念(Sebesta Ch-5.4.3.1)を読んだ後に頭に浮かび、::と書かれています。

静的修飾子がC++、Java、およびC#のクラス定義の変数の宣言に含まれている場合、それは変数の存続期間とは関係がないことに注意してください。その文脈では、それは変数がインスタンス変数ではなくクラス変数であることを意味します。予約語を複数回使用すると、特にその言語を学ぶ人にとっては混乱を招く可能性があります。

わかりましたか?:(

4

5 に答える 5

17

後でリンクできるように、初期化についてもいくつかのテキストを書きたいと思います。


まず可能性のリスト。

  • 名前空間静的
  • クラス静的
  • ローカル静的

名前空間静的

  • 2 つの初期化方法があります。静的(コンパイル時に発生することを意図) および動的(実行時に発生することを意図) 初期化。
  • 静的初期化は、翻訳単位の関係を無視して、動的初期化の前に行われます。
  • 動的初期化は翻訳単位で順序付けされますが、静的初期化には特定の順序はありません。同じ翻訳単位の名前空間スコープのオブジェクトは、定義が表示される順序で動的に初期化されます。
  • 定数式で初期化される POD 型オブジェクトは、静的に初期化されます。それらの値は、翻訳単位の関係を無視して、任意のオブジェクトの動的初期化によって依存できます。
  • 初期化で例外がスローされた場合は、std::terminateが呼び出されます。

例:

次のプログラムは印刷しますA(1) A(2)

struct A { 
  A(int n) { std::printf(" A(%d) ", n); } 
};

A a(1);
A b(2);

そして、以下は同じクラスに基づいて出力されますA(2) A(1)

extern A a;
A b(2);
A a(1);

msg次のように定義されている翻訳単位があるとしましょう。

char const *msg = "abc";

次に、次のように表示されabcます。p動的初期化を受け取ることに注意してください。しかし、静的初期化 (char const*は POD 型で、"abc"はアドレス定数式)msgがその前に行われるため、これは問題なく、msg正しく初期化されることが保証されています。

extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
  • main の前にオブジェクトの動的な初期化を行う必要はありません。ただし、初期化は、オブジェクトまたはその翻訳単位の関数を最初に使用する前に行う必要があります。これは、動的にロード可能なライブラリーにとって重要です。

クラス静的

  • 名前空間の static のように動作します。
  • 関数またはその翻訳単位のオブジェクトの最初の使用時にコンパイラがクラス statics を初期化できるかどうかについてのバグ レポートもあります (main の後)。標準の文言では、現在、名前空間スコープ オブジェクトに対してのみこれを許可していますが、クラス スコープ オブジェクトに対してもこれを許可することを意図しているようです。Namespace Scope のオブジェクトを読み取ります。
  • テンプレートのメンバーであるクラス static のルールは、それらが使用された場合にのみ初期化されるというものです。それらを使用しないと、初期化されません。いずれの場合も、上記で説明したように初期化が行われることに注意してください。テンプレートのメンバーであるため、初期化が遅れることはありません。

ローカル静的

  • ローカル スタティックの場合、特別なルールが発生します。
  • 定数式で初期化された POD 型オブジェクトは、それらが定義されているブロックに入る前に初期化されます。
  • 他のローカル静的オブジェクトは、制御が定義を最初に通過するときに初期化されます。例外がスローされた場合、初期化は完了したとは見なされません。次回から再度初期化を試みます。

例: 次のプログラムは次のように出力し0 1ます。

struct C { 
  C(int n) { 
    if(n == 0)
      throw n;
    this->n = n;
  }
  int n;
};

int f(int n) {
  static C c(n);
  return c.n;
}

int main() {
  try { 
    f(0); 
  } catch(int n) { 
    std::cout << n << " "; 
  }
  f(1); // initializes successfully
  std::cout << f(2);  
}

上記のすべてのケースで、特定の限定的なケースでは、静的に初期化する必要のない一部のオブジェクトについて、コンパイラーは動的に初期化する代わりに静的に初期化できます。これは難しい問題です。より詳細な例については、この回答を参照してください。

また、破壊の順序は、オブジェクトの構築が完了した正確な順序であることに注意してください。これはよくあることで、一時オブジェクトの破棄を含め、C++ のあらゆる状況で発生します。

于 2009-07-03T17:15:59.987 に答える
15

通常の静的(グローバル)変数とまったく同じです。

于 2009-07-03T14:33:44.330 に答える
5

グローバル変数が構築され、グローバル変数とともに破棄されるのと同時に構築されます。

于 2009-07-03T14:34:46.217 に答える
3

簡単に言えば
、グローバル変数が構築されると、静的メンバー変数が構築されます。グローバル変数の構築順序は定義されていませんが、メイン関数に入る前に発生します。

グローバル変数が破棄されると、破棄が発生します。

グローバル変数は、構築された順序とは逆の順序で破棄されます。メイン関数を終了した後。

よろしく、
オバネス

PS: C++-Standard を参照することをお勧めします。これは、グローバルまたは静的メンバー変数がいつ、どのように構築または破棄されるかを説明 (定義) しています。

PPS: あなたのコードは静的メンバー変数のみを宣言していますが、初期化はしていません。それを初期化するには、コンパイル単位の 1 つに書き込む必要があります。

std::vector Test::staticVector;
または
std::vector Test::staticVector=std::vector(/* ctor params here */);

于 2009-07-03T15:07:52.860 に答える
1

使用している場合の特定の VC++ 情報:

  1. 静的クラス変数の構築は、他の静的/グローバル変数と同時に発生します。
  2. Windows では、CRT スタートアップ関数がこの構築を担当します。これは、コンパイルするほとんどのプログラムの実際のエントリ ポイントです (Main/Winmain 関数を呼び出す関数です)。さらに、C ランタイム サポート全体の初期化を担当します (たとえば、malloc を使用するために必要です)。
  3. 構築の順序は定義されていませんが、Microsoft VC コンパイラを使用する場合、基本型の構築の順序は問題ありません。たとえば、合法で安全に記述できます。

statics.h: ... MyClass 宣言 ... static const int a; 静的 int b; static int ar[]; statics.cpp:

const int MyClass::a = 2;
int MyClass::b = a+3;
int MyClass::ar[a] = {1,2}
于 2009-07-03T15:17:15.833 に答える