在解析器文件中定义union时,为什么我们使用指针来表示复杂类?

时间:2016-08-02 09:30:53

标签: c++ pointers bison unions

我正在研究RDDL的解析器,并且正如我之前所做的那样,当我定义包含我使用的类型的union时,我使用指针。 E.g。

%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;
}

这是我看到大多数人在解析器中实现多个令牌类型的方式。在网上搜索这个答案时,我所看到的只是示例,并没有解释为什么我们必须使用指针。我现在的任务之一就是清理指针&#39;哪里有可能。所以我的问题是,在这种情况下,为什么我们(必须)在联合中使用指针?

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

2 个答案:

答案 0 :(得分:4)

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

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

  1. sizeof union_t必须至少与最大会员一样大。所以你不希望联合使用一个单词int和一些1KB的值。指针几乎总是固定的小尺寸。

  2. 在C ++世界中,许多类(对于您的示例,std::stringstd::vector)具有非平凡的复制构造函数和析构函数。

  3. 对于这些类,将它们组合在一起是不安全的。 C ++ 11为此提供了一个“解决方案”,称为unrestricted unions。但即使这样,它也不会按原样运行:对于union_t object的每次赋值和销毁,你必须明确地破坏/构造一个活跃的联盟成员。

答案 1 :(得分:1)

非平凡对象无法存储在联合中,因此只要使用%union,就必须使用指针。但是,Bison 3提供了一种基于变体的替代方案,可以让您免于使用指针。

所以而不是

%union
{
  int ival;
  std::string* sval;
}
%token <ival> NUMBER;
%token <sval> STRING;
你会写

%define api.value.type variant
%token <int> NUMBER;
%token <std::string> STRING;

有关详情,请参阅Bison官方文档中的A Complete C++ Example