ロード時に多数のクラスをファクトリに登録しようとしています。私の戦略は、静的初期化を利用して、main()が開始する前に、ファクトリが準備ができていることを確認することです。この戦略は、ライブラリを動的にリンクする場合は機能するようですが、静的にリンクする場合は機能しません。静的にリンクすると、静的データメンバーの一部のみが初期化されます。
私の工場が自動車を製造しているとしましょう。少数の車をインスタンス化できるCarCreatorクラスがありますが、すべてではありません。工場でこれらのCarCreatorクラスをすべて収集して、新しい車を探すコードが、実際の建設を誰が行うかを知らなくても工場に行くことができるようにしたいと思います。
だから私は持っています
CarTypes.hpp
enum CarTypes
{
prius = 0,
miata,
hooptie,
n_car_types
};
MyFactory.hpp
class CarCreator
{
public:
virtual Car * create_a_car( CarType ) = 0;
virtual std::list< CarTypes > list_cars_I_create() = 0;
};
class MyFactory // makes cars
{
public:
Car * create_car( CarType type );
void factory_register( CarCreator * )
static MyFactory * get_instance(); // singleton
private:
MyFactory();
std::vector< CarCreator * > car_creator_map;
};
MyFactory.cpp
MyFactory:: MyFactory() : car_creator_map( n_car_types );
MyFactory * MyFactory::get_instance() {
static MyFactory * instance( 0 ); /// Safe singleton
if ( instance == 0 ) {
instance = new MyFactory;
}
return instance;
}
void MyFactory::factory_register( CarCreator * creator )
{
std::list< CarTypes > types = creator->list_cars_I_create();
for ( std::list< CarTypes >::const_iteator iter = types.begin();
iter != types.end(); ++iter ) {
car_creator_map[ *iter ] = creator;
}
}
Car * MyFactory::create_car( CarType type )
{
if ( car_creator_map[ type ] == 0 ) { // SERIOUS ERROR!
exit();
}
return car_creator_map[ type ]->create_a_car( type );
}
..。
次に、特定の車と特定の車の作成者を紹介します。
Miata.cpp
class Miata : public Car {...};
class MiataCreator : public CarCreator {
public:
virtual Car * create_a_car( CarType );
virtual std::list< CarTypes > list_cars_I_create();
private:
static bool register_with_factory();
static bool registered;
};
bool MiataCreator::register_with_factory()
{
MyFactory::get_instance()->factory_register( new MiataCreator );
return true;
}
bool MiataCreator::registered( MiataCreator::register_with_factory() );
..。
繰り返しになりますが、ライブラリを動的にリンクすると、MiataCreator :: registeredが初期化され、ライブラリを静的にリンクしますが、初期化されません。
静的ビルドでは、誰かがMiataを要求するためにファクトリに行くと、willのmiata要素はcar_creator_map
NULLを指し、プログラムは終了します。
プライベート静的積分データメンバーに、初期化が何らかの理由でスキップされるという特別なものはありますか?静的データメンバーは、クラスが使用されている場合にのみ初期化されますか?私のCarCreatorクラスはどのヘッダーファイルでも宣言されていません。それらは完全に.cppファイル内にあります。コンパイラが初期化関数をインライン化し、どういうわけかMyFactory ::の呼び出しを回避している可能性はありますfactory_register
か?
この登録の問題に対するより良い解決策はありますか?
すべてのCarCreatorを単一の関数にリストし、それぞれをファクトリに明示的に登録してから、関数が呼び出されることを保証するオプションはありません。特に、いくつかのライブラリをリンクし、これらの別々のライブラリでCarCreatorsを定義したいのですが、それでも単一のファクトリを使用してそれらを構築します。
..。
これが私が予想しているが私の問題に対処していないいくつかの応答です:
1)シングルトンファクトリはスレッドセーフではありません。a)関係ありませんが、私は単一のスレッドのみを使用しています。
2)CarCreatorsが初期化されているときにシングルトンファクトリが初期化されていない可能性があります(つまり、静的初期化の大失敗があります)a)シングルトンインスタンスを関数に入れることで、安全なバージョンのシングルトンクラスを使用しています。これが問題である場合、MiataCreator's::register_with_factory
メソッドにprintステートメントを追加すると、出力が表示されるはずです。そうではありません。