2017-07-24 67 views
2

我正在使用访问者模式的中型C++框架。这些访问方法为什么导致内存泄漏?

执行此框架的程序的valgrind测试报告了大量内存泄漏,可以追踪到其中一个访问者,即copyCreator

template<typename copyNodeType> 
struct copyCreator { 
    copyCreator {} 
    copyCreator(node * firstVisit) { 
     firstVisit->accept(*this); 
    } 

    ~copyCreator() { 
     copy.reset(); 
     for(auto ptr : openList) { 
      delete ptr; 
     } 
    } 

    std::unique_ptr<copyNodeType> copy = 0; 
    vector<nonterminalNode *> openList; 

    // push to tree 
    template<typename nodeType> 
    void push(nodeType * ptr) { 
     if (copy) { 
      // if root is set, append to tree 
      openList.back()->add_child(ptr); 
     } 
     else { 
      auto temp = dynamic_cast<copyNodeType *>(ptr); 
      if(temp) { 
       copy = std::unique_ptr<copyNodeType>(temp); 
      } 
     } 
    } 

// ... 

    void visit(struct someNonterminalNode & nod) { 
    auto next = new someNonterminalNode(); //This is leaked 
    push(next); 
    openList.push_back(next); 
    nod.child->accept(*this); 
    openList.pop_back(); 
}; 

有,为什么我感到困惑的这两个主要的原因:

  • 两个不同的构造导致不同数量的泄漏
  • 泄漏报告访问期间发生

所有节点的accept方法只是简单地触发正确访问者的visit方法的标准双重调度。

我对C++编程相当陌生,可能忽略了一些真正的基本问题。

+1

我可以看到为什么'copyCreator cpy2(&globalScope,a);'会泄漏。 'copyCreator '预计它访问的第一个节点的类型是'T'。它创建并立即泄漏所有其他节点类型,直到遇到它的第一个“T”。但'a'不是'programNode'。 –

回答

2

copyCreator<nodeType>::push(ptr)应该取得ptr的所有权。但是,如果(a)ptr的类型不是nodeType*(由dynamic_cast确定),并且(b)没有访问类型为nodeType的节点,则不能这样做。

换句话说,copyCreator<nodeType>创建并立即泄漏所有节点的副本,直到遇到nodeType类型的副本。

这正是发生在copyCreator<programNode> cpy2(&globalScope, a);,其中aforallNode*cpy2预计遇到programNode(它永远不会),同时,它复制并泄漏所有其他节点。

+0

优秀的答案,我完全忽略了! 我在push方法中的dynamic_cast检查后添加了一个else {delete ptr;},并且所有泄漏都消失了。 :) 事后仍然有一些奇怪的事发生,但是我想这是因为删除的指针仍然在某处被错误地访问......我应该能够处理它。 非常感谢您的帮助,这是非常appreachiated! – mrclng