2016-10-18 5 views
15

C++ 11 a permis l'utilisation de types de mise en page standard en fonction union: Member of Union has User-Defined ConstructorEst-ce un destructeur de membres de l'Union appelé

Ma question est alors: Suis-je assuré le destructor personnalisé sera appelé, lorsque le union sort de portée?

Ma compréhension est que nous devons manuellement détruire et construire lors du passage: http://en.cppreference.com/w/cpp/language/union#Explanation

Mais qu'en est un exemple comme celui-ci:

{ 
    union S { string str; 
       vector<int> vec; 
       ~S() {} } s = { "Hello, world"s }; 
} 

Lorsque s est hors de portée, ai-je fui la mémoire du chaîne allouée sur le tas parce que je n'ai pas appelé le destructeur string?

+0

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

+0

@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 * . –

+1

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

Répondre

10

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

+0

Donc, cela dit que le constructeur de copie 'union' sera supprimé s'il a un membre avec un constructeur de copie personnalisé droit? Mais ce n'est pas ce que je vois ici: http://ideone.com/Cf0OOQ –

+0

@JonathanMee Vous devez essayer de l'appeler: http: //coliru.stacked-crooked.com/a/656b9885a04be262 – NathanOliver

+0

@JonathanMee Le constructeur de copie existe, mais il est supprimé de sorte que le code sera toujours compilé jusqu'à ce que vous essayiez de faire une copie. Il échoue à compiler lorsque le destructeur est supprimé car tout a besoin d'un destructeur. – NathanOliver

3

Votre exemple ne sera pas compilé. Les syndicats ont, par défaut, un destructeur supprimé. Parce que, bien sûr, quel destructeur devrait être appelé? Vous ne pouvez certainement pas appeler les deux. Et aucune information n'est stockée sur le membre qui a été réellement construit. C'est à vous de fournir un destructeur approprié.

est ici la sortie de GCC lorsque vous essayez de compiler votre extrait de code:

In function ‘int main()’: 
error: use of deleted function ‘main()::<anonymous union>::~<constructor>()’ 
     vector<int> vec; } s = { "Hello, world"s }; 
               ^

note: ‘main()::<anonymous union>::~<constructor>()’ is implicitly deleted because the default definition would be ill-formed: 
     union { string str; 
      ^
+0

Merci pour le commentaire. code en question, pour ajouter un destructeur personnalisé à la définition 'union'. [Ceci construit] (http://ideone.com/Cf0OOQ) alors merci pour l'info, mais cette réponse ne tente pas d'adresser le ques tion: Que se passe-t-il lorsque le «syndicat» sort du champ d'application? –

1

Vous devez toujours appeler manuellement le constructeur des objets de votre structure avec des types non triviaux.

Habituellement, vous devez toujours aussi les construire explicitement. Il semble étrange que la tâche fonctionne ici.

En cas de doute, vous pouvez toujours vérifier l'assemblage si les destructeurs sont appelés.

L'assembly de ce code appelle le constructeur basic_string mais pas le destructeur. Donc, vous aurez des fuites ici.

using namespace std; 
int main(int argc, char** argv){ 
    union S { string str; 
       vector<int> vec; 
       ~S() {} } s = { "Hello, world"s }; 
} 

lien pour voir l'ensemble: https://godbolt.org/g/wKu3vf

+0

Il s'avère donc qu'il y a une raison pour laquelle les compilateurs initialisent le 'union': http://stackoverflow.com/questions/40106941/is-union-members-destructor-called/40107282?noredirect=1#comment67502209_40107282 –