11
votes

Comment puis-je gérer les appels de sortie () dans le code de bibliothèque 3ème partie?

Je travaille sur une application C ++ qui utilise une bibliothèque écrite en C par une autre équipe. Les écrivains de la bibliothèque aiment appeler quitter () lorsque les erreurs se produisent, ce qui finit le programme immédiatement sans appeler les destructeurs d'objets sur la pile dans l'application C ++. L'application définit certaines ressources système qui ne sont pas automatiquement récupérées par le système d'exploitation après la fin du processus (régions de mémoire partagées, mutiles interprocesses, etc.), c'est donc un problème.

J'ai un code source complet pour l'application et la bibliothèque, mais la bibliothèque est très bien établie et n'a aucun test d'unité, ce qui changera que ce serait une grosse affaire. Existe-t-il un moyen de "accrocher" les appels vers sortie () afin que je puisse mettre en œuvre l'arrêt gracieux pour mon application?

Une possibilité que je envisage de faire une grande classe qui est l'application - c'est-à-dire que tout nettoyage se produirait soit dans son destructeur, soit dans le destructeur de l'un de ses membres - alors allouant l'une de ces gros objets sur le tas dans Main () , définir un pointeur global pour le pointer et utiliser atexit () pour enregistrer un gestionnaire qui supprime simplement l'objet via le global aiguille. Est-ce que cela devrait fonctionner?

Y a-t-il un bon moyen connu d'aborder ce problème?


0 commentaires

4 Réponses :



4
votes

Installer le gestionnaire de sortie avec Atexit et implémenter le comportement souhaité


1 commentaires

J'ai pensé à cela (c'est dans la question). Le problème est que les variables locales de chaque fonction de la pile d'appel ne sont pas disponibles à un simple gestionnaire - d'où mes pensées sur la création de l'application elle-même un seul objet attribué sur le tas et supprimables via un pointeur global.



2
votes

Si vous souhaitez rendre la bibliothèque C plus utilisable de C ++, vous pouvez peut-être l'exécuter dans un processus distinct. Assurez-vous ensuite (avec un gestionnaire de sortie ou autrement) que lorsqu'il sort, votre processus d'application principal notit et jette une exception pour dérouler sa propre pile. Peut-être dans certains cas, il pourrait gérer l'erreur d'une manière non mortelle.

Bien entendu, déplacer l'utilisation de la bibliothèque dans un autre processus pourrait ne pas être facile ou particulièrement efficace. Vous aurez du travail à faire pour envelopper l'interface et de copier des entrées et des sorties via le mécanisme IPC de votre choix.

En tant que solution de contournement pour utiliser la bibliothèque à partir de votre processus principal, je pense que celui que vous décrivez devrait fonctionner. Le risque est que vous ne pouvez pas identifier et isoler tout ce qui nécessite de nettoyer, ou que quelqu'un à l'avenir modifie votre application (ou un autre composant que vous utilisez) sur l'hypothèse que la pile sera déroutée normalement.

vous pourrait modifier la source de la bibliothèque pour appeler une fonction d'exécution ou de la compilée-configurable au lieu d'appeler sortie () . Ensuite, compilez la bibliothèque avec une manipulation d'exception et implémentez la fonction en C ++ pour lancer une exception. Le problème avec c'est que la bibliothèque elle-même modifie probablement des ressources sur l'erreur, vous devez donc utiliser cette exception seulement pour dérouler la pile (et peut-être faire des rapports d'erreur). Ne l'attrapez pas et continuez même si l'erreur pourrait être non mortelle aussi fatale que votre application est concernée.


0 commentaires

1
votes

Si l'appel EXIT et non affirmez ou Abandon , il y a quelques points pour obtenir un contrôle à nouveau:

  • Lorsque vous appelez Quitter , les destructeurs des objets avec une durée de vie statique (essentiellement: globaux et objets déclarés avec statique ) sont toujours exécutés. Cela signifie que vous pouvez configurer un (quelques) objet (s) mondial (s) de «gestionnaire de ressources» et publier les ressources dans leur (s) destructeur (s).
  • Comme vous l'avez déjà trouvé, vous pouvez enregistrer des crochets avec atexit . Cela ne se limite pas à un. Vous pouvez vous inscrire plus.

    Si tout le reste échoue, car vous avez la source de la bibliothèque, vous pouvez lire des astuces macro pour remplacer efficacement les appels à Quitter avec une fonction de votre choix qui pourrait, par exemple, lancer une exception.


0 commentaires