C++ 访问者模式是否应用于共享指针或原始指针?

C++ 访问者模式是否应用于共享指针或原始指针?,c++,design-patterns,C++,Design Patterns,我正在做一个小编译器。现在我有了一个层次结构系统来表示抽象语法树(AST) 共享ptr 使用AstNode=shared\u ptr; 使用BinaryOpNode=shared\u ptr; 类访客{ 公众: 虚拟AstNode访问(AstNode ast); 虚拟AstNode visitBinaryOp(二进制操作节点二进制){ 访问(二进制->左侧); 访问(二进制->rhs); // ... } } 类Ast:公共启用\u共享\u{ 公众: 虚拟AstNode接受(AstVisitor

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

共享ptr
使用AstNode=shared\u ptr;
使用BinaryOpNode=shared\u ptr;
类访客{
公众:
虚拟AstNode访问(AstNode ast);
虚拟AstNode visitBinaryOp(二进制操作节点二进制){
访问(二进制->左侧);
访问(二进制->rhs);
// ...
}
}
类Ast:公共启用\u共享\u{
公众:
虚拟AstNode接受(AstVisitor和visitor);
}
类二进制操作:{
公众:
虚拟AstNode接受(AstVisitor和visitor)覆盖{
return visitor.visitBinaryOp(静态指针转换(shared from_this());
}
}

接受
共享\u ptr
的函数告诉读者它复制了一份共享\u ptr,并在函数返回后保留它

函数不应采用
共享\u ptr
,除非它们复制了它

我认为由B.Stroustrup和H.Sutter编辑的这篇文章将有助于解决这个问题。 请注意:

R.30:仅将智能指针作为参数来显式表示生存期语义

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

例如,在您的
BinaryOp
类中,使用
shared_ptr
管理子节点是一种很好的做法。 每个节点都有它的父节点作为所有者,这些
shared_ptr
s使用RAII语义保持子树的活动状态。(
std::unique_ptr
更可取,因为每个节点都有一个单一的父节点,它是一个所有者。)


另外,由于您的
visit
visitBinaryOp
似乎只需要
Ast
BinaryOp
本身,因此在这种情况下,最好接受一个原始指针(或一个引用,如果可能的话)可能您误解了
语言律师
标记。这是关于语言规则的问题(除了修复编译器错误之外),这里并不适用。您可能希望将您的想法与之进行比较,或者简单地使用
std::variant
。它可以为您节省大量代码行和时间。访问者可以很好地接受引用。@BitTickler您能更清楚地解释一下吗?凭直觉,我猜AST层次结构系统的大多数类对其子树都有
唯一的\u ptr
语义,但我不确定在进一步分析时它们是否都有唯一的语义。@user8510613 thx:)。虽然这只是我的经验,但我很少需要使用std::shared\u ptr。当我想使用指针时,我的第一选择几乎总是std::unique\u ptr,它使所有权关系和代码更加清晰。但我认为这肯定取决于您的实现细节。我希望你一切顺利。
class Ast{
public:
    // ...
}

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

using ExprNode = shared_ptr<Expr>;

class BinaryOp : public Expr{
public:
    ExprNode lhs;
    ExprNode rhs;
}
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);
    }
}
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()));
    }
}