Je travaille sur une application moyenne embarquée en C utilisant des techniques de type OO. Mes "classes" sont des modules .h / .c utilisant des structures de données et des structures de pointeurs de fonction pour émuler l'encapsulation, le polymorphisme et l'injection de dépendances.
Maintenant, on pourrait s'attendre à ce qu'une myModule_create(void)
fonction vienne avec une myModule_destroy(pointer)
contrepartie. Mais le projet étant intégré, les ressources qui sont instanciées de manière réaliste ne devraient jamais être libérées.
Je veux dire, si j'ai 4 ports série UART et que je crée 4 instances UART avec leurs broches et paramètres requis, il n'y a absolument aucune raison de vouloir détruire UART # 2 à un moment donné pendant l'exécution.
Donc, en suivant le principe YAGNI (vous n'en aurez pas besoin), dois-je omettre les destructeurs? Cela me semble extrêmement étrange mais je ne peux pas penser à une utilisation pour eux; les ressources sont libérées lorsque l'appareil s'éteint.
la source
myModule_create(void)
fonction? Vous pouvez simplement coder en dur les instances spécifiques que vous prévoyez d'utiliser dans l'interface que vous exposez.Réponses:
Glampert a raison; il n'y a pas besoin de destructeurs ici. Ils ne feraient que créer du ballonnement de code et un piège pour les utilisateurs (l'utilisation d'un objet après l'appel de son destructeur est un comportement non défini).
Cependant, vous devez être sûr qu'il n'est vraiment pas nécessaire de jeter les objets. Par exemple, avez-vous besoin d'un objet pour un UART qui n'est pas actuellement utilisé?
la source
Le moyen le plus simple que j'ai trouvé pour détecter les fuites de mémoire est de pouvoir quitter proprement votre application. De nombreux compilateurs / environnements offrent un moyen de vérifier la mémoire qui est toujours allouée lorsque votre application se ferme. Si aucun n'est fourni, il existe généralement un moyen d'ajouter du code juste avant de quitter, ce qui peut le comprendre.
Donc, je fournirais certainement des constructeurs, des destructeurs et une logique d'arrêt même dans un système embarqué qui "théoriquement" ne devrait jamais sortir pour faciliter la détection de fuite de mémoire seule. En réalité, la détection de fuite de mémoire est encore plus importante si le code d'application ne doit jamais quitter.
la source
Dans mon développement, qui fait un usage intensif de types de données opaques pour favoriser une approche de type OO, je me suis trop débattu avec cette question. Au début, j'étais décidément dans le camp de l'élimination du destructeur du point de vue YAGNI, ainsi que du point de vue du "code mort" de la MISRA. (J'avais beaucoup d'espace pour les ressources, ce n'était pas une considération.)
Cependant ... l'absence d'un destructeur peut rendre les tests plus difficiles, comme dans les tests unitaires / d'intégration automatisés. Classiquement, chaque test doit prendre en charge une configuration / démontage afin que les objets puissent être créés, manipulés, puis détruits. Ils sont détruits afin d'assurer un point de départ propre et intact pour le test suivant. Pour ce faire, la classe a besoin d'un destructeur.
Par conséquent, d'après mon expérience, le «n'est pas» dans YAGNI se révèle être un «sont» et j'ai fini par créer des destructeurs pour chaque classe, que je pensais en avoir besoin ou non. Même si j'ai sauté les tests, au moins un destructeur correctement conçu existe pour le pauvre slob qui me suit en aura un. (Et, à une valeur bien moindre, il rend le code plus réutilisable dans la mesure où il peut être utilisé dans un environnement où il serait détruit.)
Bien que cela concerne YAGNI, cela ne concerne pas le code mort. Pour cela, je trouve qu'une macro de compilation conditionnelle quelque chose comme #define BUILD_FOR_TESTING permet au destructeur d'être éliminé de la version de production finale.
Pour ce faire, vous disposez d'un destructeur pour les tests / réutilisation future, et vous répondez aux objectifs de conception de YAGNI et aux règles "sans code mort".
la source
Vous pourriez avoir un destructeur sans opération, quelque chose comme
puis définissez le destructeur d'
Uart
utiliser peut - être(ajoutez la fonte appropriée si nécessaire)
N'oubliez pas de documenter. Peut-être que tu veux même
Alternativement, cas spécial dans le code commun appelant destructeur le cas où la fonction de pointeur du destructeur est
NULL
d'éviter de l'appeler.la source