C++ C+中的工厂和动态分配问题+;
我有一个工厂,它在我的应用程序中构建生命周期最长的对象。它们有类型,比如说,C++ C+中的工厂和动态分配问题+;,c++,design-patterns,factory,C++,Design Patterns,Factory,我有一个工厂,它在我的应用程序中构建生命周期最长的对象。它们有类型,比如说,ClientA和ClientB,它们依赖于Provider(一个包含许多可能实现的抽象类),因此两个客户端都引用Provider作为成员 根据命令行参数,工厂选择提供程序的一个实现,构造它(使用“new”),并将其传递给两个客户端的构造函数 工厂返回一个表示我的整个应用程序的对象。我的主要功能基本上是: int main(int argc, char** argv) { AppFactory factory(ar
ClientA
和ClientB
,它们依赖于Provider
(一个包含许多可能实现的抽象类),因此两个客户端都引用Provider作为成员
根据命令行参数,工厂选择提供程序的一个实现,构造它(使用“new
”),并将其传递给两个客户端的构造函数
工厂返回一个表示我的整个应用程序的对象。我的主要功能基本上是:
int main(int argc, char** argv)
{
AppFactory factory(argc, argv);
App app = factory.buildApp();
return app.run();
}
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;
}
而buildApp
方法基本上是这样的:
int main(int argc, char** argv)
{
AppFactory factory(argc, argv);
App app = factory.buildApp();
return app.run();
}
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;
}
因此,当执行结束时,将调用除provider对象之外的所有对象的析构函数(因为它是用“new
”构造的)
如何改进此设计以确保调用提供程序的析构函数
编辑:澄清一下,我的意图是让客户端、提供商和应用程序对象共享相同的生命周期。在回答了所有问题之后,我现在认为应该在堆上为客户端和提供者分配其传递给App对象的引用,而App对象将负责在其死亡时删除它们。您觉得怎么样?将provider作为AppFactory的实例变量。然后将提供程序设置为智能指针或在AppFactory的dtor中删除它。只需调用
delete provider;
provider = NULL;
在ClientA和ClientB的析构函数中。这也将调用提供程序的析构函数。这里没有足够的帮助,但是在不做太多更改的情况下,您可以向提供程序对象添加引用计数,当客户端被析构函数时,它们会删除引用。当提供者对象中的引用变为0时,调用delete this
你的生命周期和范围有点粗略。为什么要在堆栈上创建一些对象,在堆上创建一些对象,特别是在客户机上 除非应用程序的构造函数复制客户端,否则它们也需要新建()-当前的客户端在堆栈上分配,并在返回应用程序时删除
我认为您可能需要注意正在创建哪些对象—例如,将调试语句放入客户机的构造函数中
您可能想要的是使提供者被引用计数,并且让每个客户机只减少引用计数,但这需要大量的工作
或者让AppFactory拥有提供程序。一个选项是让工厂返回包含工厂构造的所有组件的AppComponents对象。也就是说,类似这样的事情:
int main(int argc, char** argv)
{
AppFactory factory(argc, argv);
AppComponents components = factory.buildApp();
return components.getApp().run();
}
AppComponents类将负责删除提供程序和其他对象。将提供程序作为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();
}
使用共享所有权智能指针非常简单:
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-AppFactory::buildApp()
{
boost::共享的ptr提供者;
如果(某些条件)
{
重置(新ProviderX());
}
其他的
{
provider.reset(新ProviderY());
}
ClientA ClientA(供应商);
客户B客户B(供应商);
App App(客户A、客户B);
返回应用程序;
}
假设应用程序对象拥有客户端,并且客户端都共享一个提供者。然后,让客户端使用共享\u ptr
,而不是提供者&
。只要仍然存在拥有提供程序对象的共享\u ptr副本,该对象就不会被释放
最好不要复制clientA和clientB,也不要通过返回值来复制app,而是将客户端移动到app中,并将app本身移动到返回的对象中。这将是可能的即将到来的C++版本。但目前,要么让它们成为指针(使用shared_ptr),要么继续复制它们。另一种选择是使用auto_ptr,它具有伪所有权转移语义。但该模板存在一些固有的问题。所以你应该避免使用它 > P>你说“提供者和应用程序对象共享相同的生命周期”,但是要注意,在C++中,下面的代码片段…
App app(clientA, clientB);
return app;
。。。正在返回应用程序对象的副本:因此(取决于编译器,请参见示例)实际上可能有两个应用程序对象实例(一个在AppFactory::buildApp()方法内,另一个在主函数内)
为了回答您的问题,我想我同意您的编辑:将指向提供者的指针传递到您的应用程序构造函数中,将其存储为应用程序实例的成员数据,并在销毁应用程序实例时将其删除。除此之外,您还可以更改代码以确保不复制应用程序实例:例如,在堆上分配应用程序实例,更改AppFactory::buildApp()方法以返回指向应用程序的指针,并删除主函数末尾的应用程序实例。这并不能解释在不同时间调用DTOR的原因。对于多线程应用程序来说也是不安全的。。。最好使用引用计数或其他方法。主题外:在析构函数中删除指针后,将其设置为NULL没有任何价值。@Marcin:要解释一下吗?析构函数是在对象生命周期中调用的最后一个对象。执行后,周围没有有效的对象。如果在多个类中使用指向该对象的指针,每个类都试图删除该对象,删除后必须将其设置为NULL,否则下一个类将尝试删除已解除分配的内存。我认为提供程序和客户端之间的关系比提供程序和应用程序工厂更好。。。你是在暗示一种以前不存在的任意关系。你是在说应用程序的生命周期是工厂的范围。如果以后发生变化怎么办?实际上,范围是提供者聚合用户的生命周期。在这种情况下,是客户机…我同意依赖性不应该在工厂上——如果fac