我正在研究一个使用访问者模式的中型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 ++编程的新手,可能忽略了一些非常基本的问题。
答案 0 :(得分:2)
copyCreator<nodeType>::push(ptr)
应该取得ptr
的所有权。但是,如果(a)ptr
不是nodeType*
类型(由dynamic_cast
确定),并且(b)类型nodeType
没有类型的节点,则它无法执行此操作访问了。
换句话说,copyCreator<nodeType>
创建并迅速泄漏所有节点的副本,直到遇到nodeType
类型的节点。
这正是copyCreator<programNode> cpy2(&globalScope, a);
中发生的情况,其中a
是forallNode*
。 cpy2
期望遇到programNode
(它从未做过),同时,它会复制并泄漏所有其他节点。