Je cherche une réponse pour C# et C++. (en C#, remplacez 'destructor' par 'finalizer')
Réponses
Trop de publicités?Préambule : Herb Sutter a rédigé un excellent article sur le sujet :
http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-c-c-and-java/
C++ : Oui et non
Alors que le destructeur d'un objet ne sera pas appelé si son constructeur lâche l'affaire (l'objet n'a "jamais existé"), les destructeurs de ses objets internes peuvent être appelés.
En résumé, toutes les parties internes de l'objet (c'est-à-dire les objets membres) auront leur destructeur appelé dans l'ordre inverse de leur construction. Chaque chose construite à l'intérieur du constructeur n'aura pas son destructeur appelé à moins que RAII soit utilisé d'une manière ou d'une autre.
Par exemple :
struct Class
{
Class() ;
~Class() ;
Thing * m_pThing ;
Object m_aObject ;
Gizmo * m_pGizmo ;
Data m_aData ;
}
Class::Class()
{
this->m_pThing = new Thing() ;
this->m_pGizmo = new Gizmo() ;
}
L'ordre de la création sera :
- Le constructeur de m_aObject sera appelé.
- Le constructeur de m_aData sera appelé.
- Le constructeur de la classe est appelé
- A l'intérieur du constructeur de la classe, m_pThing aura son constructeur new et then appelé.
- A l'intérieur du constructeur de la classe, m_pGizmo aura son constructeur new et then appelé.
Disons que nous utilisons le code suivant :
Class pClass = new Class() ;
Quelques cas possibles :
-
Si m_aData échoue à la construction, le destructeur de m_aObject sera appelé. Ensuite, la mémoire allouée par "new Class" est désallouée.
-
Si m_pThing lance une nouvelle Chose (sans mémoire), m_aData, puis m_aObject verront leurs destructeurs appelés. Ensuite, la mémoire allouée par new Class est désallouée.
-
Si m_pThing échoue à la construction, la mémoire allouée par "new Thing" sera désallouée. Ensuite, les destructeurs de m_aData, puis de m_aObject seront appelés. Ensuite, la mémoire allouée par new Class est désallouée.
-
Si m_pGizmo échoue à la construction, la mémoire allouée par "new Gizmo" sera désallouée. Ensuite, les destructeurs de m_aData, puis de m_aObject seront appelés. Ensuite, la mémoire allouée par new Class est désallouée. Notez que m_pThing a fui
Si vous voulez offrir la garantie de base des exceptions, vous ne devez pas fuir, même dans le constructeur. Ainsi, vous devrez écrire ceci de cette façon (en utilisant STL, ou même Boost) :
struct Class
{
Class() ;
~Class() ;
std::auto_ptr<Thing> m_pThing ;
Object m_aObject ;
std::auto_ptr<Gizmo> m_pGizmo ;
Data m_aData ;
}
Class::Class()
: m_pThing(new Thing())
, m_pGizmo(new Gizmo())
{
}
Ou même :
Class::Class()
{
this->m_pThing.reset(new Thing()) ;
this->m_pGizmo.reset(new Gizmo()) ;
}
si vous voulez/devez créer ces objets dans le constructeur.
Ainsi, quel que soit l'endroit où le constructeur est lancé, rien ne sera divulgué.
Le destructeur de la classe en cours de construction n'est pas appelé, car l'objet n'a jamais été entièrement construit.
Cependant, le destructeur de sa classe de base (s'il existe) EST appelé, car l'objet a été construit jusqu'à être un objet de classe de base.
De plus, les destructeurs de toutes les variables membres seront également appelés (comme d'autres l'ont noté).
NB : ceci s'applique à C++
En C++, la réponse est non - le destructeur de l'objet est no appelé.
Cependant, les destructeurs de toutes les données membres de l'objet se sera appelé, sauf si l'exception a été levée lors de la construction d'un des éléments suivants les .
En C++, les données des membres sont initialisées (c'est-à-dire construites) dans l'ordre dans lequel elles sont déclarées. Ainsi, lorsque le constructeur se lance, toutes les données des membres qui ont été initialisées - que ce soit explicitement dans la liste d'initialisation des membres (MIL) ou autrement - seront à nouveau détruites dans l'ordre inverse.