C++ 在解析器文件中定义联合时,为什么要对复杂类使用指针?

C++ 在解析器文件中定义联合时,为什么要对复杂类使用指针?,c++,pointers,bison,unions,C++,Pointers,Bison,Unions,我正在为开发一个解析器,正如我以前所做的那样,当我定义包含我使用的类型的union时,我使用指针。例如 %union { double d; int i; std::string *str; std::vector<std::string> *vectorStr; RDDLBlock *rddlBlock; Domain *domain; DefineType *defineType; std::vector<D

我正在为开发一个解析器,正如我以前所做的那样,当我定义包含我使用的类型的union时,我使用指针。例如

%union {
    double d;
    int i;
    std::string *str;
    std::vector<std::string> *vectorStr;

    RDDLBlock *rddlBlock;
    Domain *domain;
    DefineType *defineType;
    std::vector<DefineType*> *vectorDefineType;
    DomainList *domainList;
    std::vector<PvarDefinition*> *vectorPvarDefinition;
    PvarDefinition *pVarDefinition;
    CpfDefinition *cpfDefinition;
    std::vector<CpfDefinition*> *vectorCpfDefinition;
    PvarExpression *pVarExpression;
    LogicalExpression *logicalExpression;
    std::vector<LogicalExpression*> *vectorLogicalExpression;
    LConstCaseList *lConstCaseList;
    CaseDefine *caseDefine;
    std::vector<CaseDefine*> *vectorCaseList;
    Parameter *parameter;
    ParameterList *parameterList;

    ObjectDefine *objectDefine;
    std::vector<ObjectDefine*> *objectsList;
    PvariablesInstanceDefine* pvariablesInstanceDefine;
    std::vector<PvariablesInstanceDefine*> *pvariablesInstanceList;

    Instance *instance;
    NonFluentBlock *nonFluentBlock;
}
%union{
双d;
int i;
std::string*str;
std::vector*vectorStr;
RDDLBlock*RDDLBlock;
域*域;
DefineType*DefineType;
std::vector*vectorDefineType;
域名列表*域名列表;
std::vector*vectorPvarDefinition;
PvarDefinition*PvarDefinition;
CPFD定义*CPFD定义;
std::vector*VectorCPFD定义;
PvarExpression*PvarExpression;
LogicalExpression*LogicalExpression;
std::vector*vectorLogicalExpression;
LConstCaseList*LConstCaseList;
CaseDefine*CaseDefine;
标准::矢量*矢量病例表;
参数*参数;
参数列表*参数列表;
ObjectDefine*ObjectDefine;
std::vector*objectsList;
PvariablesInstanceDefine*PvariablesInstanceDefine;
std::vector*pvariablesInstanceList;
实例*实例;
非流块*非流块;
}
这就是我看到大多数人在解析器中实现多种令牌类型的方式。在网上搜索这个答案时,我看到的只是一些例子,没有解释为什么我们必须使用指针。我现在的任务之一就是在可能的地方“清理指针”。所以我的问题是,在这种情况下,为什么我们(必须)在联合中使用指针


编辑:添加了union中定义的类型的完整列表。

您不必使用指针。如您所见,
double
int
都不是指针

至于“我们为什么使用”部分,我们应该记住
union
的一些属性

  • 工会的大小必须至少与最大成员的大小相同。因此,您不希望与单个单词
    int
    和一些1KB的值类合并。指针几乎总是有固定的小尺寸

  • <> L> >P>在C++世界中,很多类(对于您的例子, STD::String 和)具有非平凡的复制构造函数和析构函数。
    对于这样的类,将它们合并是不安全的。C++11为此提供了一个“解决方案”,称为。但即使这样,它也不会按原样工作:对于
    联合对象的每次赋值和销毁,您必须显式地销毁/构造一个活动的联合成员。

    您不必使用指针。如您所见,
    double
    int
    都不是指针

    至于“我们为什么使用”部分,我们应该记住
    union
    的一些属性

  • 工会的大小必须至少与最大成员的大小相同。因此,您不希望与单个单词
    int
    和一些1KB的值类合并。指针几乎总是有固定的小尺寸

  • <> L> >P>在C++世界中,很多类(对于您的例子, STD::String 和)具有非平凡的复制构造函数和析构函数。
    对于这样的类,将它们合并是不安全的。C++11为此提供了一个“解决方案”,称为。但即使这样,它也不会按原样工作:对于
    联合对象的每次赋值和销毁,您必须显式地销毁/构造活动的联合成员。

    非平凡对象不能存储在联合中,因此只要您使用
    %union
    ,就必须使用指针。然而,Bison3提供了一个基于变体的替代方案,它使您不必使用指针

    所以不是

    %union
    {
      int ival;
      std::string* sval;
    }
    %token <ival> NUMBER;
    %token <sval> STRING;
    
    %union
    {
    国际竞争力;
    std::string*sval;
    }
    %令牌号;
    %令牌串;
    
    你会写信吗

    %define api.value.type variant
    %token <int> NUMBER;
    %token <std::string> STRING;
    
    %define api.value.type变量
    %令牌号;
    %令牌串;
    

    有关详细信息,请参阅Bison文档中的。

    非平凡对象不能存储在联合中,因此只要使用
    %union
    ,就必须使用指针。然而,Bison3提供了一个基于变体的替代方案,它使您不必使用指针

    所以不是

    %union
    {
      int ival;
      std::string* sval;
    }
    %token <ival> NUMBER;
    %token <sval> STRING;
    
    %union
    {
    国际竞争力;
    std::string*sval;
    }
    %令牌号;
    %令牌串;
    
    你会写信吗

    %define api.value.type variant
    %token <int> NUMBER;
    %token <std::string> STRING;
    
    %define api.value.type变量
    %令牌号;
    %令牌串;
    

    有关更多详细信息,请参阅Bison文档中的。

    如果您不知道为什么必须这样做,则可能不必这样做,因为解析堆栈中没有大量元素。如果你的元素不是很大,那就不用麻烦了
    Domain*Domain
    。@LưuVĩnhPhúc这也是要做的更改之一。@EJP切换到非指针类型的主要原因不是到处都是指针,而是到处都是对象实例。如果你不知道为什么要这样做,您可能不必这样做,因为解析堆栈上没有大量元素。如果你的元素不是很大,那就不用麻烦了
    Domain*Domain
    。@LưuVĩnhPhúc这也是要做的更改之一。@EJP切换到非指针类型的主要原因不是有一堆指针,而是有一堆对象实例。谢谢你的回答!在我把它标记为正确之前,我想问一个小问题。由于我的联合体中既有std::string类型,也有std::vector类型(我将用完整的类型列表更新问题),这将取决于编译器,因此不是每个人都能用默认编译器编译它。该项目在完成后将是开放源代码的,在没有许多额外设置的情况下准备好运行和编译是很重要的。@Đ或đeRelić,我错了,它现在是标准的。但是,有很多注意事项——你需要仔细考虑每个拷贝、赋值和销毁<代码>联合< /COD>对象。在我看来,这不值得努力,最好把指针留在原地。谢谢你的回答!在我把它标记为正确之前,我想问一下