この問題には、私には明らかではない単純な解決策があると思います.iniファイルからロードされたさまざまな構成オプションを他の場所に格納するために使用される構成クラスがあります。私のアプリケーションには、ライブラリとクライアント、および 2 つの構成があります。ライブラリを DLL としてビルドし、クライアントを動的にリンクさせるか、両方を 1 つのバイナリとして一緒にビルドします。では、ライブラリとクライアントの両方で構成オブジェクトを使用/使用するにはどうすればよいですか? 両方に構成クラス定義を含めると、再定義によるリンク エラーが発生すると思います。
1 に答える
両方に構成クラス定義を含めると、再定義によるリンク エラーが発生すると思います。
いいえ、そうはなりません。Windows DLL は、1 つの定義規則を尊重しません。基本的に、Windows では、ODR はモジュールの境界で停止します。つまり、ODR は実行可能ファイル内およびDLL 内で考慮されますが、それらをまたがっては考慮されません。それが良いことかどうかは関係ありません。したがって、DLL と実行可能ファイルの両方に構成クラスの定義を含めることができます。ただし、各モジュールに 1 つずつ、シングルトンの 2 つの個別のインスタンスがあります (構成クラスは通常、シングルトン クラスであると想定しています)。その意味では、少なくともモジュール間では真のシングルトンにはなりません。
モジュール全体で真のシングルトンが必要な場合は、もう少し作業を行う必要があります。マスター/スレーブまたはマージ (または「デイジー チェーン」) の 2 つの選択肢があります。
最初のオプションは、シングルトン オブジェクトをインスタンス化 (および保持) するモジュールとして 1 つのモジュール (実行可能ファイルなど) を指定し、そのインスタンスへのポインターをすべての「スレーブ」モジュールに渡します。共通インターフェース (つまり、両方のモジュールが構成クラスに対して同じ宣言を持っていますが、1 つのモジュールだけがそれを作成して他のモジュールに渡します)。次のようになります。
ヘッダー ファイル "config_class.h" 内:
class ConfigClass {
// a bunch of declarations...
public:
static ConfigClass& getInstance(); // the access-point for the singleton.
};
#ifdef MY_LIB_NOW_BUILDING_MASTER
extern "C" __declspec(dllimport) void setConfigClassInstance(ConfigClass* pobj);
#else
extern "C" __declspec(dllexport) void setConfigClassInstance(ConfigClass* pobj);
#endif
cpp ファイル "config_class.cpp" 内:
#include "config_class.h"
// a bunch of definitions for the config_class member functions.
#ifdef MY_LIB_NOW_BUILDING_MASTER
ConfigClass& ConfigClass::getInstance() {
static ConfigClass instance( /* */ );
return instance;
};
#else
static ConfigClass* masterInstance;
void setConfigClassInstance(ConfigClass* pobj) {
masterInstance = pobj;
};
ConfigClass& ConfigClass::getInstance() {
return *masterInstance;
};
#endif
上記の例では、マスター モジュール (ほとんどの場合、メインの実行可能ファイル) から setConfigClassInstance を呼び出して、DLL の構成オブジェクトを設定しますが、DLL が静的な初期化 (読み込み) 中に構成クラスを必要としないことを確認します。 .
2 番目のオプションは、シングルトンをマージまたはデイジー チェーン接続することです。この場合、各モジュールは独自のシングルトン インスタンスを作成しますが、上記と同様のスキームを使用して、相互のインスタンスへのポインターを渡し、それらを 1 つのインスタンスにマージ (相互リンク) するか、それらを連鎖させることができます。 (たとえば、循環リンク リストまたはリング リストのように) 呼び出しを適切なインスタンスにディスパッチします。
あなたのアプリケーションでは、最初のオプションがおそらく最も簡単だと思います。
注意: Windows 以外の環境では、状況はまったく異なり、上記のいずれも当てはまりません。