3

アプリケーションで最長の寿命を持つオブジェクトを構築するファクトリがあります。これらには、 (多くの可能な実装を持つ抽象クラス)に依存する型、たとえば、ClientAおよびがあるため、両方のクライアントは、メンバーとして Provider への参照を持ちます。ClientBProvider

コマンドライン引数に従って、ファクトリは の 1 つの実装を選択しProvider、それを (" new" で) 構築し、両方のクライアントのコンストラクタに渡します。

ファクトリは、アプリ全体を表すオブジェクトを返します。私の主な機能は基本的にこれです:

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    App app = factory.buildApp();
    return app.run();
}

そして、そのbuildApp方法は基本的に次のとおりです。

App AppFactory::buildApp()
{
    Provider* provider = NULL;

    if (some condition)
    {
        provider = new ProviderX(); 
    }
    else
    {
        provider = new ProviderY();
    }

    ClientA clientA(*provider);
    ClientB clientB(*provider);

    App app(clientA, clientB);
    return app;
}

そのため、実行が終了すると、プロバイダ オブジェクトを除くすべてのオブジェクトのデストラクタが呼び出されます (" new" で構築されたため)。

この設計を改善して、プロバイダーのデストラクタが確実に呼び出されるようにするにはどうすればよいですか?

編集:明確にするために、私の意図は、クライアント、プロバイダー、および App オブジェクトの両方が同じ寿命を共有することです。すべての回答の後、クライアントとプロバイダーの両方をヒープに割り当てて、 App オブジェクトに渡された参照を割り当てる必要があると思います。これは、死んだときにそれらを削除する責任があります。あなたは何を言っていますか?

4

8 に答える 8

3

共有所有権のスマート ポインターを使用すると、非常に簡単です。

App AppFactory::buildApp()
{
    boost::shared_ptr<Provider> provider;

    if (some condition)
    {
        provider.reset(new ProviderX()); 
    }
    else
    {
        provider.reset(new ProviderY());
    }

    ClientA clientA(provider);
    ClientB clientB(provider);

    App app(clientA, clientB);
    return app;
}

アプリ オブジェクトがクライアントを所有し、すべてのクライアントが 1 つのプロバイダーを共有すると仮定します。クライアントが のshared_ptr<Provider>代わりに then を取得するようにしますProvider&。プロバイダー オブジェクトを所有する shared_ptr のコピーが残っている限り、オブジェクトは解放されません。

最善の方法は、clientA と clientB をコピーせず、app を値で返すことによってコピーせず、クライアントをアプリに移動し、アプリ自体を返されたオブジェクトに移動することです。これは、今後の C++ バージョンで可能になります。しかし現在は、(shared_ptr を使用して) それらをポインターにするか、それらをコピーし続けます。もう 1 つのオプションは、所有権の疑似転送セマンティックを持つ auto_ptr を使用することです。しかし、そのテンプレートには固有の問題がいくつかあります。したがって、使用を避ける必要があります。

于 2008-12-30T06:03:03.403 に答える
2

provider を AppFactory のインスタンス変数にします。次に、プロバイダーをスマート ポインターにするか、AppFactory の dtor で削除します。

于 2008-12-29T21:00:44.467 に答える
2

アプリのコンストラクターがクライアントをコピーしない限り、クライアントも new() する必要があります。現在のクライアントはスタックに割り当てられ、アプリが返されると削除されます。

どのオブジェクトが作成されているかについて注意する必要があると思います-たとえば、クライアントのコンストラクターにデバッグステートメントを入れます。

おそらく必要なのは、プロバイダーを参照カウントにして、各クライアントで参照カウントを減らすだけですが、それは大変な作業です。

または、AppFactory がプロバイダーを所有するようにします。

于 2008-12-29T21:38:03.487 に答える
1

provider を AppFactory のメンバー変数にし、デストラクタで削除します。

class AppFactory
{
    public:
    AppFactory(int argc, char** argv) : provider(NULL)
    {
       //...
    }
    ~AppFactory()
    {
        if (provider != NULL)
            delete provider;
    }
    App buildApp()
    {

        if (some condition)
        {
            provider = new ProviderX(); 
        }
        else
        {
            provider = new ProviderY();
        }

        ClientA clientA(*provider);
        ClientB clientB(*provider);

        App app(clientA, clientB);
        return app;

    } 
    private:
    Provider* provider;

};

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    App app = factory.buildApp();
    return app.run();
}
于 2008-12-29T22:25:19.100 に答える
1

オプションは、ファクトリが構築するすべてのコンポーネントを含む AppComponents オブジェクトをファクトリに返すようにすることです。つまり、次のようなものです。

int main(int argc, char** argv)
{
    AppFactory factory(argc, argv);
    AppComponents components = factory.buildApp();
    return components.getApp().run();
}

その後、AppComponents クラスは、プロバイダやその他のオブジェクトを削除する責任を負います。

于 2008-12-29T22:00:55.563 に答える
1

「プロバイダーと App オブジェクトが同じ有効期間を共有する」と言っていますが、C++ では次のコード フラグメントに注意してください...

App app(clientA, clientB);
return app;

... App オブジェクトのコピーを返しているため、(コンパイラによっては、たとえばhttp://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspxを参照してください)実際には 2 つの App オブジェクト インスタンスがあります (1 つは AppFactory::buildApp() メソッド内にあり、もう 1 つは main 関数内にあります)。

あなたの質問に答えるために、私はあなたの編集に同意すると思います:プロバイダーへのポインターをアプリコンストラクターに渡し、それをアプリインスタンスのメンバーデータとして保存し、アプリインスタンスを破棄するときに削除します。ただし、これと同様に、App インスタンスをコピーしないようにコードを変更することもできます。たとえば、App インスタンスをヒープに割り当て、AppFactory::buildApp() メソッドを変更して、へのポインターを返します。 App を削除し、メイン関数の最後で App インスタンスを削除します。

于 2008-12-30T06:25:15.467 に答える
1

ここではあまり役に立ちませんが、あまり変更しなくても、Provider オブジェクトに参照カウントを追加できます。クライアントが破棄されると、クライアントは参照を削除します。Provider オブジェクトで参照が 0 になったら、delete this を呼び出します。

あなたの寿命と範囲は少し大雑把です。なぜいくつかのオブジェクトをスタックに作成し、いくつかのオブジェクトをヒープに作成するのですか?具体的にはクライアントですか?

于 2008-12-29T21:02:33.917 に答える
0

電話するだけ

delete provider;
provider = NULL;

ClientA と ClientB のデストラクタで。これは、プロバイダのデストラクタも呼び出します。

于 2008-12-29T21:01:33.763 に答える