Question

Quel comportement négatif / indéfini pourrait survenir, de l'appel d'une fonction de sauvegarde (ALA Boost-sérialisation) dans ~ dtor d'une classe?

Était-ce utile?

La solution

Vous avez deux préoccupations, dont l'une est une conséquence de l'autre:

1) Vous ne devez autoriser aucune exception à échapper au destructeur. Si vous le faites, et si le destructeur est appelé dans le cadre du déroulement de Stack, alors l'exécution terminate() votre programme. Ce n'est pas un comportement indéfini, mais c'est assez négatif.

Pour cette raison (et bien sûr parce que les destructeurs ne renvoient pas de valeur):

2) Il n'y a aucun moyen raisonnable pour votre destructeur d'indiquer le succès ou l'échec (signification "raisonnable", sans construire une sorte de système de rapport d'erreur distinct). Étant donné que l'utilisateur de votre classe pourrait vouloir savoir si la sauvegarde s'est produite ou non, de préférence avec une API raisonnable pour le faire, cela signifie que les destructeurs ne peuvent enregistrer que des données sur une base de "meilleur effort". Si la sauvegarde échoue, l'objet est toujours détruit, et donc probablement ses données sont perdues.

Il existe une stratégie pour de telles situations, utilisée par exemple par des flux de fichiers. Cela fonctionne comme ceci:

  • avoir un flush() (ou dans votre cas save()) Fonction qui enregistre les données
  • Appelez cette fonction à partir du destructeur si l'objet n'a pas déjà été enregistré / rincé (ou plus probablement: appelez-le inconditionnellement, mais demandez à la fonction elle-même de savoir s'il doit faire un travail réel ou non). Dans le cas des flux de fichiers, cela se produit via close(). Catchez toutes les exceptions qu'il peut lancer et ignorer les erreurs.

De cette façon, les utilisateurs qui ont besoin de savoir si la sauvegarde a réussi ou non save() découvrir. Les utilisateurs qui ne se soucient pas (ou qui ne le dérangeraient pas de réussir si possible dans le cas qu'une exception est lancée et que l'objet est détruit dans le cadre du déroulement de la pile) peut laisser le destructeur essayer.

C'est-à-dire votre destructeur boîte Essayez de faire quelque chose qui pourrait échouer, comme un dernier effort, mais vous devez en outre fournir aux utilisateurs un moyen de faire la même chose "correctement", d'une manière qui les informe du succès ou de l'échec.

Et oui, cela signifie accidentellement que l'utilisation de flux sans les rincer et vérifier l'état du flux pour l'échec ne les utilise pas "correctement", car vous n'avez aucun moyen de savoir si les données ont jamais été écrites ou non. Mais il y a des situations où c'est assez bon, et dans le même genre de situation, il pourrait être assez bon pour que votre classe économise dans son destructeur.

Autres conseils

Le problème est que boost-serialize peut lancer une exception. Cela signifie que si le destructeur est appelé parce qu'une exception se propage et nettoie la pile au fur et à mesure qu'elle se détend, votre application se terminera si le destructeur de l'objet lance une autre exception.

Donc, pour résumer, vous ne voulez toujours qu'une seule exception se propageant à la fois. Si vous vous retrouvez avec plus de plus, votre application se terminera, ce qui bat le but des exceptions.

C'est une mauvaise idée.

  1. Un destructeur ne devrait jamais lancer, Les opérations IO sont très susceptibles de lancer car si Io réussit ou non est essentiellement hors de votre contrôle.
  2. Pour moi au moins c'est extrêmement inutile
    un. D'une part, il garantit que chaque objet de ce type sera sérialisé (sauf si le destructeur a des chèques pour empêcher cela)
    né Les destructeurs ont un objectif très clair, pour nettoyer, le stockage des données est essentiellement l'opposé du nettoyage.

Je veux donc juste faire un point de plus, que devez-vous gagner en sérialisation dans le destructeur.


Vous savez que la sérialisation s'exécutera même s'il y a une exception, si vous utilisez RAII. Mais ce n'est pas tant un avantage car même si le destructeur fonctionnera, vous ne pouvez pas garantir que le sérialisation fonctionnera car il lance (dans ce cas au moins). Vous perdez également une grande partie de la capacité de gérer correctement une défaillance.

Non, ce n'est pas une mauvaise idée, mais ce n'est pas non plus une très bonne idée! Mais parfois, c'est la bonne chose à faire.

Tant que vous protégez votre destructeur contre les exceptions, il n'y a rien contre lui.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top