56 votes

Pourquoi le compilateur n'autorise pas std :: string à l'intérieur de l'union?

je veux utiliser des chaînes de caractères à l'intérieur de l'Union. si j'écris comme ci-dessous

union U
{
   int i;
   float f;
   string s;
};

Compilateur donne une erreur en disant: U::S a constructeur de copie.

J'ai lu un autre post pour d'autres moyens pour résoudre ce problème. Mais je veux savoir pourquoi le compilateur ne permet pas ceci en premier lieu?

EDIT: @KennyTM: Dans toute l'union, si le membre est initialisé d'autres auront des ordures valeurs, si aucun n'est initialisé toutes les ordures des valeurs. Je pense que, tagged union fournit simplement un peu de réconfort à l'accès valide les valeurs de l'Union. Votre question: comment avez-vous, ou le compilateur écrire un constructeur de copie pour l'union ci-dessus sans information supplémentaire? sizeof(string) donne 4 octets. Sur cette base, le compilateur ne peut pas comparer les autres membres de tailles et d'allouer plus grande répartition(4 octets dans notre exemple). Interne de la longueur de la chaîne n'a pas d'importance, car il va être stocké dans un emplacement séparé. Laissez la chaîne de la longueur. Tout ce que l'Union a savoir, c'est en invoquant la classe string constructeur de copie avec le paramètre de chaîne. Dans n'importe quelle manière que le compilateur trouve que le constructeur de copie doit être invoqué dans le cas normal, méthode similaire à être suivie, même lorsque la chaîne est à l'intérieur de l'Union. Donc, je pense compilateur pourrait faire comme, allouer 4 octets. Alors si une chaîne est affectée à s, puis en classe string prendra soin de répartition et de la copie de cette chaîne à l'aide de son propre allocateur. Donc, il n'y a aucune chance de corruption de la mémoire ainsi.

Est une chaîne n'existait pas au moment de l'Union de développement dans le compilateur ? Donc la réponse n'est pas claire pour moi encore. Je suis un nouvel arrivant sur ce site, si quelque chose de mal, pls de bien vouloir m'excuser.

73voto

KennyTM Points 232647

Car le fait d'avoir une classe avec un non-trivial (copier/)constructeur dans une union qui n'a pas de sens. Supposons que nous avons

union U {
  string x;
  vector<int> y;
};

U u;  // <--

Si U est un struct, u.x et u.y serait initialisé à une chaîne vide et le vecteur vide, respectivement. Mais les membres d'un syndicat de partager la même adresse. Donc, si u.x est initialisé, u.y contiennent des données non valides, et donc, c'est l'inverse. Si les deux d'entre eux ne sont pas initialisé alors qu'ils ne peuvent pas être utilisés. En tout cas, le fait d'avoir ces données dans un syndicat ne peut pas être manipulé facilement, de sorte que C++98 choisit de le nier: (§9.5/1):

Un objet d'une classe avec un non-trivial constructeur (12.1), un non-trivial constructeur de copie (12.8), un non-trivial destructeur (12.4), ou à un non-trivial copie opérateur d'affectation (13.5.3, 12.8) ne peut pas être membre d'un syndicat, ni un tableau de ces objets.

Dans C++0x cette règle a été assouplie (§9.5/2):

Tout au plus un non-membre de données statiques d'une union peut avoir un corset ou égal initialiseur. [Note: si une non-statique des données de membre d'un syndicat a un non-trivial de constructeur par défaut (12.1), le constructeur de copie (12.8), constructeur de déplacement (12.8), copie opérateur d'affectation (12.8), de les déplacer opérateur d'affectation (12.8), ou le destructeur (12.4), la fonction de membre de l'union doit être fourni par l'utilisateur ou qu'il va être supprimés de manière implicite (8.4.3) pour l'union. - la note de fin ]

mais il n'est toujours pas possible de créer (correct) con/destructeurs pour l'union, par exemple, comment avez-vous, ou le compilateur écrire un constructeur de copie pour l'union ci-dessus sans information supplémentaire? Pour assurer le membre de l'union est active, vous avez besoin d'un tagged de l'union, et que vous avez besoin pour gérer la construction et la destruction manuellement par ex.

struct TU {
   int type;
   union {
     int i;
     float f;
     std::string s;
   } u;

   TU(const TU& tu) : type(tu.type) {
     switch (tu.type) {
       case TU_STRING: new(&u.s)(tu.u.s); break;
       case TU_INT:    u.i = tu.u.i;      break;
       case TU_FLOAT:  u.f = tu.u.f;      break;
     }
   }
   ~TU() {
     if (tu.type == TU_STRING)
       u.s.~string();
   }
   ...
};

Mais, comme @DeadMG a mentionné, ce qui est déjà mis en œuvre en tant que boost::variant ou boost::any.

30voto

Puppy Points 90818

Pensez-y. Comment le compilateur sait-il quel type est dans l'union?

Ce n'est pas le cas. Le fonctionnement fondamental d'une union est essentiellement une distribution au niveau du bit. Les opérations sur les valeurs contenues dans les unions ne sont sûres que lorsque chaque type peut essentiellement être rempli de déchets. std::string ne peut pas, car cela entraînerait une corruption de la mémoire. Utilisez boost::variant ou boost::any .

16voto

Keats Points 8938

En C ++ 98/03, les membres d'une union ne peuvent pas avoir de constructeurs, de destructeurs, de fonctions membres virtuelles ou de classes de base.

Donc, fondamentalement, vous ne pouvez utiliser que des types de données intégrés ou des POD

Notez qu'il change en C ++ 0x: unions sans restriction

 union {
    int z;
    double w;
    string s;  // Illegal in C++98, legal in C++0x.
};
 

8voto

FireAphis Points 2705

De la spécification C ++ §9.5.1:

Un objet d'une classe avec un constructeur non trivial, un constructeur de copie non trivial, un destructeur non trivial ou un opérateur d'affectation de copie non triviale ne peut pas être membre d'une union.

La raison de cette règle est que le compilateur ne saura jamais lequel des destructeurs / constructeurs appelle, car il ne sait jamais vraiment lequel des objets possibles se trouve à l'intérieur de l'union.

3voto

ccSadegh Points 2885

Il n'y a pas de raison ... mais dans la norme suivante (C ++ 0x), vous pouvez le faire sans aucun problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X