在基于yacc的解析器中防止内存泄漏的最佳方法是什么?
Yacc不允许传递对象。因为%union只能包含POD类型,所以必须对复杂对象进行新建并通过指针进行传递。如果发生语法错误,则yacc解析器将停止运行,并且将丢失对所有这些创建对象的引用。
我想出的唯一解决方案是,所有新对象都继承一个特定的基类,在分配时将其添加到容器中,如果出现错误,则可以删除该容器中的所有内容。
有谁知道解决这个问题的更好的yacc技巧?
请不要告诉我选择其他解析器。
解决方案
回答
如果适合项目,请考虑使用Boehm垃圾收集器。这样,我们可以自由分配新对象,并让收集器处理删除操作。当然,使用垃圾收集器需要权衡取舍。我们将不得不权衡成本和收益。
回答
使用智能指针!
或者,如果我们对另一个库感到不舒服,则可以始终使用C ++标准库中的auto_ptr。
回答
我爱Yacc,但有区别的联合会确实提出了挑战。
我不知道我们使用的是C还是C ++。我已经修改了Yacc以生成C ++用于我自己的目的,但是此解决方案可以适应C。
我的首选解决方案是将接口传递给解析树下的所有者,而不是将构造的对象传递到堆栈上。为此,可以在Yacc之外创建自己的堆栈。在调用分配对象的非终端设备之前,请将该对象的所有者推入该堆栈。
例如:
class IExpressionOwner { public: virtual ExpressionAdd *newExpressionAdd() = 0; virtual ExpressionSubstract *newExpressionSubtract() = 0; virtual ExpressionMultiply *newExpressionMultiply() = 0; virtual ExpressionDivide *newExpressionDivide() = 0; }; class ExpressionAdd : public Expression, public IExpressionOwner { private: std::auto_ptr<Expression> left; std::auto_ptr<Expression> right; public: ExpressionAdd *newExpressionAdd() { ExpressionAdd *newExpression = new ExpressionAdd(); std::auto_ptr<Expression> autoPtr(newExpression); if (left.get() == NULL) left = autoPtr; else right = autoPtr; return newExpression; } ... }; class Parser { private: std::stack<IExpressionOwner *> expressionOwner; ... };
想要表达式的所有内容都必须实现IExpressionOwner接口,并将其自身推入堆栈,然后再非终止调用表达式。它有很多额外的代码,但是它控制对象的生存期。
更新
表达式示例是一个不好的例子,因为我们只有在减少了左操作数之后才知道该操作。尽管如此,该技术在许多情况下仍然有效,并且只需要对表达式进行一些调整即可。
回答
为什么使用其他解析器会出现此问题? Bison随时可用,并且(至少在linux上)yacc通常实现为bison。我们不需要对语法进行任何更改即可使用它(添加%destructor可以解决问题除外)。