Selon un auteur expérimenté de la communauté C ++, le code ci-dessous ne devrait pas être compilé. Est-ce qu’il a tort?

Selon Herb Sutter, le code ci-dessous ne serait pas compilé. Voir ce site http://www.gotw.ca/gotw/066.htm d’où j’ai extrait le texte suivant concernant les function-try-blocks :

Vers certaines morales

Incidemment, cela signifie également que la seule utilisation possible (pour la répétition uniquement) d’un constructeur function-try-block consiste à traduire une exception levée à partir d’un sous-object base ou membre. C’est la morale # 1. Ensuite, Moral # 2 dit que les blocs d’essais de destructeurs sont entièrement usele–

“–Mais attendez!” J’entends quelqu’un m’interrompre du milieu de la pièce. “Je ne suis pas d’accord avec Moral # 1. Je peux penser à une autre utilisation possible des blocs try-function du constructeur, à savoir libérer les ressources allouées dans la liste d’initialisation ou dans le corps du constructeur!”

Désolé, Nope. Après tout, rappelez-vous qu’une fois dans le gestionnaire try-block de votre constructeur, toutes les variables locales du corps du constructeur sont également hors de scope et vous avez la garantie qu’aucun sous-object de base ou object membre n’existe plus, point. Vous ne pouvez même pas vous référer à leurs noms. Soit les parties de votre object n’ont jamais été construites, soit celles qui ont été construites ont déjà été détruites. Vous ne pouvez donc pas nettoyer tout ce qui consiste à faire référence à une base ou à un membre de la classe (et de toute façon, c’est à quoi servent les destructeurs de la base et des membres, n’est-ce pas?).

En supposant cette citation, le code suivant ne doit pas être compilé, car l’object cat a déjà été détruit au moment où le processus s’exécute dans la clause catch . Mais c’est le cas, du moins avec VSC2008.

 class Cat { public: Cat() { cout << "Cat()" << endl; } ~Cat() { cout << "~Cat()" << endl; } }; class Dog { public: Dog() { cout << "Dog()" << endl; throw 1; } ~Dog() { cout << "~Dog()" << endl; } }; class UseResources { class Cat *cat; class Dog dog; public: UseResources(); ~UseResources() { delete cat; cat = NULL; cout << "~UseResources()" << endl; } }; UseResources::UseResources() try : cat(new Cat), dog() { cout << "UseResources()" << endl; } catch(...) { delete cat; throw; } 

Je ne pense pas que Herb Sutter dit en fait qu’il ne comstackra pas. Il vient d’expliquer les conséquences de ce que la norme dit à propos de la situation (15.3.10):

La référence à un membre non statique ou à une classe de base d’un object du gestionnaire pour un bloc fonction-essai d’un constructeur ou d’un destructeur de cet object entraîne un comportement indéfini .

En supposant que cette citation, le code suivant ne devrait pas comstackr …

Eh bien, il n’a pas dit qu’ils ne comstackraient jamais. Au contraire, j’ai interprété la citation comme signifiant “faire ceci est indéfini”. Tout comportement indéfini est autorisé à avoir un résultat quelconque – même une compilation réussie, et à faire des choses surprenantes par la suite.

Les compilateurs sont différents, et il existe également des commutateurs qui déterminent combien le compilateur sera ssortingct avec le code qu’il comstack. ce code causera certainement des erreurs (erreurs de segmentation, etc.). essayez d’activer tous les commutateurs du compilateur pour le forcer à le trouver.