静的メンバーを確実に初期化するための唯一の信頼できる方法は、関数で行うことであることをずっと前に学びました。
いいえ、そうではありません。標準はそれを保証します:
- 簡単なコンストラクターを備えた静的ストレージ(ブロックとファイルまたはクラス静的スコープの両方)を持つすべてのオブジェクトは、コードが実行される前に初期化されます。プログラムのすべてのコード。
- file / global / class-staticスコープと重要な構成を持つすべてのオブジェクトは、
main
関数が呼び出される前に初期化されます。オブジェクトAとBが同じ変換単位で定義され、AがBの前に定義されている場合、AはBの前に初期化されることが保証されます。ただし、異なる変換単位で定義されたオブジェクトの構築順序は指定されておらず、コンパイル間で異なることがよくあります。
- ブロック静的オブジェクトは、宣言に初めて到達したときに初期化されます。C ++ 03標準はスレッドをサポートしていないため、これはスレッドセーフではありません。
- 静的ストレージ(ブロックとファイル/グローバル/クラス静的スコープの両方)を持つすべてのオブジェクトは、関数が終了するか、システムコールを使用してアプリケーションが終了した後、コンストラクターが完了するのとは逆の順序で破棄されます。
main()
exit()
どちらの方法も、すべての場合に使用可能で信頼できるわけではありません。
今、私がやろうとしていることは、非定数参照によって静的データを返し始めることであり、私を止める誰かが必要です。
誰もあなたを止めるつもりはありません。それは合法であり、完全に合理的なことです。ただし、スレッドトラップに陥らないように注意してください。
たとえば、C ++用の妥当な単体テストライブラリは、すべてのテストケースを自動的に登録します。それは次のようなものを持つことによってそれを行います:
std::vector<TestCase *> &testCaseList() {
static std::vector<TestCase *> test_cases;
return test_cases;
}
TestCase::TestCase() {
...
testCaseList().push_back(this);
}
それはそれを行うための2つの方法のうちの1つだからです。もう1つは:
TestCase *firstTest = NULL;
class TestCase {
...
TestCase *nextTest;
}
TestCase::TestCase() {
...
nextTest = firstTest;
firstTest = this;
}
今回は、firstTest
自明なコンストラクターを持っているという事実を使用しているため、自明でないコンストラクターを持つsの前に初期化されます。TestCase
dataSlot()= 7; //完全に正常ですか?
はい。ただし、本当に必要な場合は、次のいずれかを実行できます。
の古いCのもの
#define dataSlot _dataSlot()
errno
「変数」は通常、ある意味で定義されます。
または、次のような構造体でラップすることもできます
class dataSlot {
Type &getSlot() {
static Type slot;
return slot;
}
operator const Type &() { return getSlot(); }
operator=(Type &newValue) { getSlot() = newValue; }
};
(ここでの欠点は、dataSlotで直接呼び出しようとすると、コンパイラがTypeのメソッドを検索しないことです。そのため、operator =が必要です)