2

3つのプロジェクトを含むアプリケーション(MS Visual Studio内)があります。

  • mainmain関数を含むもの)
  • デバイス(一部のハードウェアデバイスをモデル化)
  • config(他の両方のプロジェクトの構成が含まれています)

したがって、依存関係グラフは次のようになります。

  • mainはデバイスに依存し、これは構成に依存します
  • mainは設定に依存します

構成プロジェクトには、いくつかの構成パラメーターを保持するシングルトンが含まれています。

デバイスプロジェクトをDLLに変換することにしました。これを行ったとき、構成プロジェクトでシングルトンのインスタンスが2つ取得されたようです。これは古典的な問題だと思いますが、これには良い解決策があるかもしれません。では、どうすればこれを修正できますか?

次の(比較的小さい)コードで問題を再現しました。もちろん、私の場合、3つだけでなく30のプロジェクトがあります。そして、(可能であれば)1つのDLLだけを作成したいと思います。


// config.h
#pragma once
#include <string>
#include <map>
class Config
{
public:
    static void Initialize();
    static int GetConfig(const std::string& name);

private:
    std::map<std::string, int> data;
};

// config.cpp
#include "config.h"

static Config g_instance;

void Config::Initialize()
{
    g_instance.data["one"] = 1;
    g_instance.data["two"] = 2;
}

int Config::GetConfig(const std::string& name)
{
    return g_instance.data[name];
}

// device.h
#pragma once

#ifdef _DLL
#define dll_cruft __declspec( dllexport )
#else
#define dll_cruft __declspec( dllimport )
#endif

class dll_cruft Device
{
public:
    void Work();
};

// device.cpp
#include "device.h"
#include <iostream>
#include "config.h"

void Device::Work()
{
    std::cout << "Device is working: two = " << Config::GetConfig("two") << '\n';
}

// main.cpp
#include <iostream>
#include "config.h"
#include "device.h"

int main()
{
    std::cout << "Before initialization in application: one = " << Config::GetConfig("one") << '\n';
    Config::Initialize();
    std::cout << "After initialization in application: one = " << Config::GetConfig("one") << '\n';
    Device().Work();
    std::cout << "After working in application: two = " << Config::GetConfig("two") << '\n';
}

出力:

アプリケーションで初期化する前:one = 0

アプリケーションでの初期化後:one = 1

デバイスは機能しています:2 = 0

アプリケーションで作業した後:2 = 2

コードの機能とその理由に関する説明:

  1. メインアプリケーションが起動します
  2. 最初の印刷は、シングルトンがまだ初期化されていないことを示すためだけのものです
  3. メインアプリケーションはシングルトンを初期化します
  4. 最初の印刷は、初期化が機能したことを示しています
  5. メインアプリケーションが「ハードウェアデバイス」を起動します
  6. DLL内では、シングルトンは初期化されていません。私はそれが出力することを期待していますtwo = 2
  7. 最後の印刷は、シングルトンがまだメインアプリケーションで初期化されていることを示しています
4

3 に答える 3

2

シングルトンをどこに置くかを決定し、それを他の消費者に公開することができます。


OPによる編集:

たとえば、configインスタンスがEXEにのみ表示されるようにします(DLLには表示されません)。

  1. インスタンスをポインタに変える

    static Config* g_instance;
    
  2. deviceエクスポートされた関数に別の初期化関数を追加します。

    void InitializeWithExisting(Config* instance) {g_instance=instance;}
    
  3. シングルトンを通常どおり初期化した後、2番目の初期化を使用します。

    Config::Initialize();
    Config::InitializeWithExisting();
    
于 2012-05-09T21:37:05.003 に答える
2

この同じ問題に遭遇したとき、シングルトンインスタンスを管理することを唯一の目的とする別のDLLを作成することで問題を解決しました。シングルトンへのポインタを取得しようとするすべての試みは、この新しいDLL内の関数を呼び出します。

于 2012-05-09T17:18:19.777 に答える
-2

この方法でシングルトンインスタンスを定義してアクセスすると、問題が解決する可能性があると思います。

Config& getInstance()
{
  static Config config;
  return config;
}

このように、Initializeメソッドを用意する(そして呼び出す)必要もありません。初期化にコンストラクターを使用できます。コンストラクターは、getInstanceを初めて呼び出すときに自動的に呼び出されます。

于 2012-05-09T17:13:55.753 に答える