2016-08-02 1 views
0

Je travaille sur un analyseur pour RDDL et, comme je l'ai déjà fait, lorsque je définis une union qui contient des types que j'utilise, j'utilise des pointeurs. Par exemple.Pourquoi utilisons-nous des pointeurs pour les classes complexes lors de la définition de l'union dans un fichier parser?

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

C'est ainsi que j'ai vu la plupart des gens implémenter plusieurs types de jetons dans les parseurs. En cherchant cette réponse sur le web, tout ce que j'ai vu sont les exemples et aucune explication sur pourquoi nous devons utiliser des pointeurs. Une de mes tâches consiste maintenant à «nettoyer les pointeurs» là où c'est possible. Alors ma question est la suivante: pourquoi devons-nous (devons-nous) utiliser des indicateurs dans les syndicats dans ce cas?

EDIT: Ajout de la liste complète des types définis dans union.

+2

Si vous ne savez pas pourquoi vous devez le faire, vous n'avez probablement pas besoin de – wasthishelpful

+3

Vous n'avez donc pas d'énormes éléments sur la pile d'analyse. Si vos éléments ne sont pas énormes, ne vous embêtez pas. – EJP

+0

dans [style C++] (http://stackoverflow.com/q/6990726/995714) ce serait 'std :: string * str;', 'Domain * domain' ... –

Répondre

4

Vous n'avez pas besoin d'utiliser des pointeurs. Comme vous pouvez le voir, ni double ni int sont des pointeurs. Pour ce qui est de la partie "Pourquoi utilisons-nous", nous devrions nous souvenir de certaines propriétés de union.

  1. sizeof union_t doit être au moins aussi grand que le plus gros membre. Donc, vous ne voulez pas l'union avec un seul mot int et une classe de 1 Ko par la valeur. Et le pointeur a presque toujours une petite taille fixe.

  2. Dans le monde C++, de nombreuses classes (pour votre exemple, std::string et std::vector) ont des constructeurs de copie et des destructeurs non triviaux.

Pour de telles classes, il est dangereux de les mettre en union. C++ 11 fournit une "solution" à cela, connue sous le nom unrestricted unions. Mais même dans ce cas, il ne fonctionnera pas tel quel: pour chaque affectation et destruction de union_t object, vous devez explicitement détruire/construire un membre actif de l'union.

+0

Merci pour votre réponse! Avant de le marquer comme correct, j'aimerais poser une sous-question. Puisque j'ai les deux types std :: string et std :: vector dans mon union (je mettrai à jour la question avec la liste complète des types) ce serait quelque chose qui dépend du compilateur et donc tout le monde ne pourra pas le compiler avec leur compilateur par défaut.Le projet est censé être open source quand il est fini et il est important d'être prêt à fonctionner et à compiler sans beaucoup de paramètres supplémentaires. –

+0

@ đorđeRelić, j'avais tort, il est maintenant standard avec [union sans restriction C++ 11] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf) . Cependant, il existe de nombreuses mises en garde - vous devez examiner attentivement chaque copie, assignation et destruction de l'objet 'union'. OMI ça ne vaut pas la peine, mieux vaut laisser des pointeurs en place. – deniss

1

Les objets non triviaux ne peuvent pas être stockés dans des unions, aussi longtemps que vous utilisez %union, vous devez utiliser des pointeurs. Cependant, Bison 3 fournit une alternative basée sur une variante qui vous libère (eh eh) de l'utilisation de pointeurs.

Ainsi, au lieu de

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

vous écririez

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

Voir la A Complete C++ Example dans la documentation de Bison pour plus de détails.