使用访问者模式

时间:2017-03-10 09:12:07

标签: c++ c++11 pointers shared-ptr abstract-syntax-tree

我有一个内存管理问题。对于one of my projects我正在为一种小型编程语言构建一个解释器。最初的步骤之一是建模和构建Abstract Syntax Tree

截至目前,我正在使用智能指针管理节点的生命周期,我认为每个父节点都是其子节点的所有者,它也必须与环境共享(例如,要知道方法的主体所属的树的哪一部分)和垃圾收集器,垃圾收集器必须保留所有引用的列表以实现初始标记和扫描算法。因此,我使用std::shared_ptr来跟踪引用。例如,这是一个Block节点的示例,它基本上代表一个lambda表达式:

#ifndef NAYLANG_BLOCK_H
#define NAYLANG_BLOCK_H

#include <model/ast/expressions/Expression.h>
#include <model/ast/declarations/Declaration.h>
#include <memory>
#include <vector>

namespace naylang {

#define BlockPtr std::shared_ptr<Block>

class Block : public Expression {

    std::vector<std::shared_ptr<Statement>> _body;
    std::vector<std::shared_ptr<Declaration>> _params;

public:

    Block() = default;

    void accept(Evaluator &evaluator) override;

    const std::vector<std::shared_ptr<Statement>> &body() const;
    const std::vector<std::shared_ptr<Declaration>> &params() const;

    void addStatement(std::shared_ptr<Statement> statement);
    void addParameter(std::shared_ptr<Declaration> param);
};

} // end namespace naylang

#endif //NAYLANG_BLOCK_H

如您所见,此节点是其所有参数和正文表达式的所有者,并具有访问器,以便Evaluator可以遍历树。

现在,当尝试将在评估时绑定到其他节点的节点时出现问题,例如:

#ifndef NAYLANG_REQUEST_H
#define NAYLANG_REQUEST_H

#include <model/ast/expressions/Expression.h>
#include <string>
#include <memory>
#include <vector>
#include <model/ast/declarations/MethodDeclaration.h>

namespace naylang {

class Request : public Expression {

    std::string _name;
    std::vector<ExpressionPtr> _params;

    // We use naked pointers because we don't want to worry
    // about memory management, and there is no ownership
    // with the declaration.
    const MethodDeclaration *_binding;

public:

    Request(const std::string &methodName);
    Request(const std::string &methodName, const std::vector<ExpressionPtr> params);

    void accept(Evaluator &evaluator) override;

    void bindTo(const MethodDeclaration *_binding);

    const std::string &method() const;
    const std::vector<ExpressionPtr> &params() const;
    const MethodDeclaration &declaration() const;
};

} // end namespace naylang

#endif //NAYLANG_REQUEST_H

如您所见,bindTo()BindingEvaluator的子类)在构造之后很久就会对Request对象进行求值时调用Evaluator。但是,我真的不确定_binding参数应该是什么样子。这是Evaluator界面的一部分:

#ifndef NAYLANG_EVALUATOR_H
#define NAYLANG_EVALUATOR_H

#include <model/ast/Statement.h>

namespace naylang {

class Request;
class Block;

class Evaluator {

public:

    Evaluator() = default;
    virtual ~Evaluator() = default;

    // Methods left blank to be overridden by the subclasses.
    // For example, a Binding Evaluator might be only interested in
    // evaluating VariableReference and Request Statements

    virtual void evaluate(Request &expression) {}
    virtual void evaluate(Block &expression) {}
};    
}
#endif //NAYLANG_EVALUATOR_H

这是我的理由:

  • 引用应该是多态的,因此应该是某种指针。
  • 引用表示所有权,因此它不应该是std::shared_ptr
  • 此外,我们需要访问者模式,因此每个节点都具有函数void accept(Evaluator &evaluator);。由于节点无法返回shared_ptr自身,因此我们无法将界面更改为virtual void evaluate(std::shared_ptr<Request> &expression) {}
因此,赤裸的指针。我真的希望在继续之前做到这一点,因为每次重新思考它都会改变大量的代码(AST很冗长......)

提前谢谢。

0 个答案:

没有答案