在基于yacc的解析器中防止内存泄漏的最佳方法是什么?

时间:2020-03-05 18:54:03  来源:igfitidea点击:

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可以解决问题除外)。