【问题标题】:Circular Dependency when calling destructors调用析构函数时的循环依赖
【发布时间】:2014-08-03 14:02:40
【问题描述】:

我有以下架构,并且由于继承,当在类上调用destructors 时会导致循环依赖。

namespace IntOp
{
    ref class PwItem;
    ref class PwTag;

public ref class PwItem
{
    public:
      PwItem(void* arg1, <sometype>arg2, unsigned __int64 arg3);
      {
          // some constructor work
      }
      virtual ~PwItem(){};
      static PwItem^ PwItem::CreateItem(void* arg1, <sometype>arg2, unsigned __int64 arg3) 
     {
        if(arg2 is of type PTag)
        {  //  PTag = gcnew PwTag(arg1, arg2, arg3);
           //  return PTag;
         return gcnew PwTag(arg1, arg2, arg3);
        }
        else if(arg2 is of type PFile)
        {    //PFile = gcnew PwTag(arg1, arg2, arg3);
            // return PFile;
         return gcnew PwFile(arg1, arg2, arg3);
        }
        return gcnew PwItem(arg1, arg2, arg3);
     }

   private : 

     //PwTag^ PTag;
   //  PwFile^ PFile;  //Another type with PwItem as Base constructor
 }


public ref class PwTag : PwItem
{
    public:
    PwTag(void* arg1, <sometype>arg2, unsigned __int64 arg3) : PwItem (void* arg1, <sometype>arg2, unsigned __int64 arg3) {};
   virtual ~PwTag();
}}

所以这里,当我想在PwItem上调用一个delete,所以它释放了PwItem的实例化,然后因为继承,PwTagPwItem上调用了destructor,整个事情不断重复。

如何解决这个问题? destructor 确实需要被调用来释放类对象中的一些东西。

编辑:添加调用代码

myServer srv = new myServer();
srv.connect();
while(true)
{
    PwItem ^item = srv.GetItem(<some string>); //This will invoke the GetItem function, which will call createItem()
    System.Threading.Thread.Sleep(200);
}

实际的 GetItem() 函数

PwItem^ myServer::GetItem(<some string>)
{

    // do some work, nothing new being instantiated etc. just arguments 1, 2 and 3, which do not cause leaks
    return gcnew PwItem::CreateItem(arg1, arg2, arg3);
   // Tried instantiating a PwItem pi; return pi.CreateItem(arg1, arg2, arg3); as well. No luck
   // Bypassed PwItem entirely, and based on arg2, called return gcnew PwTag(arg1, arg2, arg3); as well, no luck
   // Tried PwItem pi, ^tempPwItem; tempPwItem = pi.CreateItem(arg1, arg2, arg3); return tempPwItem; No luck
}

【问题讨论】:

    标签: .net dependencies c++-cli destructor circular-dependency


    【解决方案1】:

    我相信您正在尝试创建工厂。但一个相当不寻常的工厂。您说您的基类根据请求的对象类型创建子类实例。但是您的代码正在做其他事情。 每个子类总是有 1 个实例吗?另外,对于每个子类,您会将其对象保留在基类(PwItem)中吗? 此外,在 CreateItem 方法中没有提到您需要哪个子实例! 假设出现了一个 PwXYZ 子类,那么您的代码将是什么? 我看到的错误之一是您在静态函数中发送 PwTag 的非静态实例。

    您在基类中只需要一个 STATIC CreateInstance 方法,该方法将获取请求的对象类型并返回该对象。无需在基​​类中保留任何子类对象。

     //You can have an ENUM >>> enum ItemType { PwTag,... so on};
      static PwItem* PwItem::CreateItem(ItemType type){
      //check which type of object is requested and simply return the instance      
    }
    

    此外,您的基类应该有一个 VIRTUAL(public) 析构函数。由于您正在为子类发送 Base 引用,如果您尝试删除它(删除带有基引用的子对象),则会导致内存泄漏,因为不会调用子类的析构函数。

    所以,现在你的基类就是

    ...
    
     public:
      PwItem();
      virtual ~PwItem(){};
      static PwItem^ PwItem::CreateItem(ItemType type) 
     {
        //switch cases OR IFs whatever you like...
        //return instance of the object requested
     }
    ...
    

    希望这会有所帮助。

    【讨论】:

    • 该设计是我继承的并导致泄漏。这个想法是,有人使用CreateObject 请求PwItem 对象,并且在该函数中,确定它是正在寻找的PwTag,因此创建了一个新的PwTag 对象并返回。基本上,基类用于实例化派生类的对象,并且它们以这种方式返回。不幸的是,假设CreateItem 之类的东西在while 循环中被调用,它会导致内存泄漏。有什么方法可以在不大修这个架构的情况下改变它?
    • 我添加了一些代码以使其更清晰。我实际上在基类中没有子类对象,它只是return gcnew &lt;child class&gt;,但由于泄漏,我想在子类的pointer 上显式调用delete,这就是我使用的原因基内子类的对象。他们(孩子和基地)不断地依次调用彼此的析构函数。
    • 没用。每次刷新仍然会泄漏 8 kb 的内存。
    • 如果我将PwItem() 构造函数保持为私有,那么子类(在这种情况下为PwTag)将如何在其自己的构造函数中访问它? PwTag(void* arg1, &lt;sometype&gt;arg2, unsigned __int64 arg3) : PwItem (void* arg1, &lt;sometype&gt;arg2, unsigned __int64 arg3) {};.
    • 是的,我的观点完全正确,因为您没有对 PwItem 类做任何事情,而是向它发送参数...现在我想您希望在 PwItem 中添加一些通用功能。现在只剩下日志了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多