TU全体でのC++の初期化は、実装の余地が大きい大きな灰色の領域であるため、完全に破棄して、いつ何が行われるかを明示することを好みます。(保証がないためにこの初期化順序が拒否されるのは、シングルトンクラスがグローバルオブジェクトを拒否する方法と似ています。)具体的には、これは、定数で初期化できないグローバル状態(グローバル変数、静的データメンバー、および関数ローカル静的)を意味します。式は正確に1つのTUで初期化する必要があり、そのTUはmainを実装するTUです。
手動の場合、これは、 mainとmain自体を含む変換ユニットにコードを挿入して更新することを意味します。このようなコードの最も一般的な例は、 std ::randPRNGsrand(time(0))
をシードするための呼び出しです。
プリプロセッサを使用して、その手動コード管理をリファクタリングできます。
// the implementation file for main, could be named main.cpp
#include "whatever_declares_the_real_main.hpp"
#include "global_objects.inc"
int main(int argc, char* argv[]) try {
#include "main_init.inc"
return the_real_main(argc, argv);
// main.cpp has well-defined responsibility:
// initialize global state before passing control to another function, and
// handle return-code or exceptions
// you can modify this, depending on your preference and desired API
// for example:
return the_real_main(std::vector<std::string>(argv+1, argv+argc));
return the_real_main(parse_args(argv+1, argv+argc));
// just make sure to keep main.cpp's responsibility well-defined and
// relatively simple
}
// example handling; depending on your specifics, you might do something
// different, or know how to provide more information:
catch (std::exception& e) {
std::cerr << "abnormal termination: " << e.what() << '\n';
return 1;
}
catch (...) {
std::cerr << "abnormal termination.\n";
return 1;
}
これらの.incファイルは、ヘッダーでも実装ファイルでもありません。.h、.hpp、.cc、.cppなど、ヘッダーや実装ファイルに一般的に使用されるものを使用しない限り、正確なファイル拡張子は重要ではありません。インクルードガードを使用して、ファイルの命名規則に基づいてglobal_objects.incとmain_init.incを生成し、依存関係を含めることができます(インクルードガードがヘッダーに対して機能するのと同じように)。
たとえば、これらのファイルは両方ともmyevent.hppに対応し、そのヘッダーの横に配置されます。
// file "myevent.global_inc"
#ifndef INCLUDE_GUARD_37E6F5857F8F47918A7C83F29A9DA868
#define INCLUDE_GUARD_37E6F5857F8F47918A7C83F29A9DA868
#include <QEvent.hpp> // or whatever headers you need
#include "myevent.hpp" // declares the variable defined just below
// (remember you use 'extern' to declare objects without defining them)
int your_namespace::myEventType = QEvent::registerEventType();
#endif
// file "myevent.main_inc"
#ifndef INCLUDE_GUARD_4F1B93D0F4D3402B802CBA433241AA81
#define INCLUDE_GUARD_4F1B93D0F4D3402B802CBA433241AA81
// nothing needed in this case, from what you've shown so far
// this is where you place expressions that would otherwise require a dummy
// global variable to make sure they are executed, but this also allows use
// of temporary variables while includes handle dependency order:
#include "something_else.main_inc" // fake example dependency, which must
{ // be executed first
int temp;
some_func(&temp);
other_func(temp); // not easy to transform this into a global's init
// expression, yet defining it this way is natural, because it's exactly
// how you would do it inside a function
}
#endif
定数式を使用した静的データの初期化のみが必要な場合は、他のすべての手法よりも優先されることに注意してください。その初期化の主な制限は、関数呼び出しを実行できないことです(ただし、実際にはもっと複雑です)。したがって、この場合は適用されません。詳細を知りたい場合は、これがCが実行できる唯一の種類のグローバル変数の初期化です。