我有一个工厂,可以在我的应用程序中构建寿命最长的对象。这些类型包括ClientA
和ClientB
,它们依赖于Provider
(具有许多可能实现的抽象类),因此两个客户端都有对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对象,它将在它死亡时负责删除它们。你怎么说?答案 0 :(得分: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对象拥有客户端,并且客户端都共享一个提供者。让客户端使用shared_ptr<Provider>
,而不是Provider&
。只要仍然拥有提供者对象的shared_ptr的副本,该对象将不会被释放。
最好不要复制clientA和clientB,也不要通过按值返回来复制应用程序,而是将客户端移动到应用程序中,然后将应用程序本身移动到返回的对象中。即将推出的C ++版本也是可能的。但是目前,你要么指向它们(使用shared_ptr),要么继续复制它们。另一个选择是使用auto_ptr,它具有伪转移所有权语义。但该模板存在一些固有问题。所以你应该避免使用它。
答案 1 :(得分:2)
使提供者成为AppFactory的实例变量。然后使提供者成为智能指针或在AppFactory的dtor中删除它。
答案 2 :(得分:2)
除非App的构造函数复制客户端,否则它们也需要new()ed - 当前的那些在堆栈上分配,并在返回应用程序时被删除。
我想您可能要小心创建哪些对象 - 例如将调试语句放在客户端的构造函数中。
你可能想要的是让提供者被引用计数,让每个客户端只减少引用计数,但这是很多工作。
或者让AppFactory拥有提供者。
答案 3 :(得分:1)
这里的帮助不够多,但是如果没有太多改变,你可以向Provider对象添加引用计数,当客户端被破坏时,它们会丢弃引用。当引用在Provider对象中变为0时,则调用delete this。
你的生命和范围有点粗略。为什么要在堆栈上创建一些对象,在堆上创建一些对象 - 特别是您的客户端?
答案 4 :(得分:1)
一个选项是让工厂返回一个包含工厂构造的所有组件的AppComponents对象。即像这样的东西:
int main(int argc, char** argv)
{
AppFactory factory(argc, argv);
AppComponents components = factory.buildApp();
return components.getApp().run();
}
然后,AppComponents类将负责删除您的提供者和其他对象。
答案 5 :(得分:1)
使提供者成为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();
}
答案 6 :(得分:1)
你说“提供者和App对象共享相同的生命周期”但要注意在C ++中,以下代码片段......
App app(clientA, clientB);
return app;
...正在返回App对象的副本:因此您可能(具体取决于编译器,请参阅http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx)实际上有两个App对象实例(一个在内部) AppFactory :: buildApp()方法和主函数内的另一个。)
要回答您的问题,我认为我同意您的编辑:将指针传递给您的App构造函数,将其存储为App实例的成员数据,并在销毁App实例时将其删除。但是,除此之外,您还可以更改代码以确保不复制App实例:例如,在堆上分配App实例,更改AppFactory :: buildApp()方法以返回指向应用程序,并删除主函数末尾的App实例。
答案 7 :(得分:0)
致电
delete provider;
provider = NULL;
在ClientS和ClientS的析构函数中。这也将调用提供者的析构函数。