访问者模式适用于shared_ptr还是原始指针?

时间:2019-01-21 10:25:18

标签: c++ design-patterns

我正在开发一个小型编译器。现在我有了一个层次结构系统来表达抽象语法树(AST)。

class Ast{
public:
    // ...
}

class Expr : public Ast{
public:
    // ...
}

using ExprNode = shared_ptr<Expr>;

class BinaryOp : public Expr{
public:
    ExprNode lhs;
    ExprNode rhs;
}

Ast层次结构系统中的所有类都使用shared_ptr来管理其成员(如果需要),例如BinaryOp拥有两个成员来表示其操作数。

我想在树上应用访客模式,以为AST生成IR代码。我的问题是,访问者应该接受原始指针作为参数,还是接受shared_ptr作为参数,这可能会导入shared_from_this(考虑利弊)?如果需要shared_ptr,我应该使用按值传递还是按引用传递?


原始指针

class AstVisitor{
public:
   virtual Ast* visit(Ast* ast);
   virtual Ast* visitBinaryOp(BinaryOp* binary){
      visit(binary->lhs.get());
      visit(binary->rhs.get());
      // ...
   }
}

class Ast{
public:
    virtual Ast* accept(AstVisitor& visitor);
}

class BinaryOp:{
public:
    virtual Ast* accept(AstVisitor& visitor) override{
        return visitor.visitBinaryOp(this);
    }
}

shared_ptr

using AstNode = shared_ptr<Ast>;
using BinaryOpNode = shared_ptr<BinaryOp>;
class AstVisitor{
public:
   virtual AstNode visit(AstNode ast);
   virtual AstNode visitBinaryOp(BinaryOpNode binary){
      visit(binary->lhs);
      visit(binary->rhs);
      // ...
   }
}

class Ast : public enable_shared_from_this<Ast>{
public:
    virtual AstNode accept(AstVisitor& visitor);
}

class BinaryOp:{
public:
    virtual AstNode accept(AstVisitor& visitor) override{
        return visitor.visitBinaryOp(static_pointer_cast<BinaryOp>(shared_from_this()));
    }
}

2 个答案:

答案 0 :(得分:3)

我认为B. Stroustrup和H. Sutter编辑的C++ Core Guidelines对于此问题会有所帮助。 请注意this guideline

  

R.30:仅将智能指针作为参数来明确表达生命周期的语义

     

原因如果该功能仅需要小部件本身,则接受指向小部件的智能指针是错误的。它应该能够接受任何窗口小部件对象,而不仅仅是那些由特定类型的智能指针管理其寿命的窗口小部件对象。不影响生命周期的函数应改用原始指针或引用。

例如,在您的BinaryOp类中,使用shared_ptr管理子节点是一个好习惯。 每个节点都有其父级作为所有者,并且这些shared_ptr通过RAII语义使子树保持活动状态。 ({std::unique_ptr会更可取,因为每个节点都有一个单亲,这是一个所有者。)

OTOH,因为您的visitvisitBinaryOp似乎只分别需要AstBinaryOp本身,所以接受原始指针(或可能的引用)在这种情况下会更合适

答案 1 :(得分:0)

接受function login () { console.log('Вы нажали ENTER') } <form> <div class="group"> <input onkeydown="if(event.keyCode == 13) login();" type="text" id="Name"> <label>Name</label> </div> <div class="group"> <input onkeydown="if(event.keyCode == 13) login();" type="text" id="Pass"> <label>Password</label> </div> <button type="button">Log In</button> </form> 的函数告诉读者它复制了一个副本,并在函数返回后将其保留。

除非复制函数,否则函数不应使用shared_ptr