Dans votre exemple, que vous avez fourni str
ne seront pas détruits. Les états standard dans [class.union]/2
Une union peut avoir des fonctions membres (y compris des constructeurs et des destructeurs), mais pas des fonctions virtuelles (10.3). Une union ne doit pas avoir de classes de base. Une union ne doit pas être utilisée comme classe de base. Si une union contient un membre de données non statique de type référence, le programme est mal formé. Au plus un membre de données non statique d'une union peut avoir un initialisateur d'accolade ou égal. [] Remarque: Si un membre de données non statique d'une union a un constructeur par défaut non trivial (12.1), copie constructeur (12.8), constructeur de déplacement (12.8), opérateur d'affectation de copie (12.8), opérateur d'affectation de déplacement (12.8) ou destructeur (12.4), la fonction membre correspondante de l'union doit être fournie par l'utilisateur ou elle sera implicitement supprimée (8.4.3) pour l'union. - Note de fin]
de Souligné par
Donc, puisque les deux str
et vec
ont des fonctions membres spéciales qui ne sont pas trivial, vous devrez leur fournir le syndicat vous.
Notez que selon bogdan's commentaires ci-dessous le destructeur vide ne suffit pas. Dans [class.union]/8 nous avons
[...] Si X est une union de ses membres variantes sont les membres de données non statiques; [...]
Donc Les membres de cette union sont des variantes. Ensuite, si nous regardons [class.dtor]/8 nous avons
Après avoir exécuté le corps du destructor et de détruire tous les objets attribués automatiquement dans le corps, une destructor pour la classe X appelle les non directe pour Destructeurs de X membres de données non statiques variables [...]
Ainsi, le destructeur ne détruira pas automatiquement les membres de l'union car ils sont des variantes.
Vous pouvez faire un tagged union comme kennytm ne here
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();
}
...
};
qui assure le membre correct est détruit ou tout simplement utiliser un std::variant
ou boost::variant
Cela ne compile pas même. AFAIK vous devez utiliser le placement nouveau pour ces choses et appeler le constructeur manuellement. Donc, pour être cohérent, il en va de même pour les destructeurs. – Hayt
@Hayt Donc, après ma modification, ce constructeur compilera: http://ideone.com/Cf0OOQ mais selon [la réponse de Nathan Oliver] (http://stackoverflow.com/a/40107282/2642059) il * fuit * . –
Je ne sais pas pourquoi l'affectation fonctionne en premier lieu. Cela semble involontaire. Mais il fuit toujours. Vous pouvez voir ici le constructeur 'basic_string' qui est appelé mais pas le destructeur: https://godbolt.org/g/2uvrWn – Hayt