3

我有一个工厂,可以在我的应用程序中构建生命周期最长的对象。比如说,它们具有ClientA依赖ClientBProvider(具有许多可能实现的抽象类)的类型,因此两个客户端都有对 Provider 的引用作为成员。

根据命令行参数,工厂选择一个实现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;
}

假设 app 对象拥有客户端,并且客户端都共享一个提供者。让客户接受 a shared_ptr<Provider>then,而不是 a Provider&。只要仍然存在拥有提供程序对象的 shared_ptr 的副本,就不会释放该对象。

最好不要复制clientA和clientB,也不要通过值返回来复制应用程序,而是将客户端移动到应用程序中,并将应用程序本身移动到返回的对象中。这将在即将推出的 C++ 版本中实现。但目前,要么将它们设为指针(使用 shared_ptr),要么继续复制它们。另一种选择是使用 auto_ptr,它具有伪所有权转移语义。但该模板存在一些固有问题。所以你应该避免使用它。

于 2008-12-30T06:03:03.403 回答
2

使提供者成为 AppFactory 的实例变量。然后将 provider 设为智能指针或在 AppFactory 的 dtor 中将其删除。

于 2008-12-29T21:00:44.467 回答
2

除非 App 的构造函数复制客户端,否则它们也需要进行 new() 处理 - 当前的客户端分配在堆栈上,并且在返回应用程序时将被删除。

我认为您可能需要注意正在创建哪些对象 - 例如将调试语句放在客户端的构造函数中。

您可能想要的是让 Provider 被引用计数,并让每个 Client 减少引用计数,但这是很多工作。

或者让 AppFactory 拥有 Provider。

于 2008-12-29T21:38:03.487 回答
1

这里并没有足够的帮助,但是您可以在不进行太多更改的情况下向 Provider 对象添加引用计数,并且当客户端被破坏时,它们会删除引用。当 Provider 对象中的引用变为 0 时,调用 delete this。

你的生命周期和范围有点粗略。为什么要在堆栈上创建一些对象,而在堆上创建一些对象——特别是你的客户?

于 2008-12-29T21:02:33.917 回答
1

一个选项是让工厂返回一个 AppComponents 对象,其中包含工厂构造的所有组件。即是这样的:

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

然后 AppComponents 类将负责删除您的 Provider 和其他对象。

于 2008-12-29T22:00:55.563 回答
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

您说“提供程序和 App 对象共享相同的生命周期”,但请注意在 C++ 中,以下代码片段...

App app(clientA, clientB);
return app;

...正在返回 App 对象的副本:因此您可以(取决于编译器,例如参见http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx )实际上有两个 App 对象实例(一个在 AppFactory::buildApp() 方法内,另一个在 main 函数内)。

为了回答您的问题,我想我同意您的编辑:将指针传递给您的 App 构造函数,将其存储为 App 实例的成员数据,并在您销毁 App 实例时将其删除。但是,除此之外,您还可以更改代码以确保不复制 App 实例:例如,在堆上分配 App 实例,更改 AppFactory::buildApp() 方法以返回指向App,并在 main 函数结束时删除 App 实例。

于 2008-12-30T06:25:15.467 回答
0

打电话

delete provider;
provider = NULL;

在 ClientA 和 ClientB 的析构函数中。这也将调用提供者的析构函数。

于 2008-12-29T21:01:33.763 回答