Je travaille dans Enviroment C ++ et:
a) Nous sommes interdits d'utiliser des exceptions
b) Il s'agit d'un code d'application / de serveur de données qui évalue beaucoup de demandes de types différents
J'ai une classification de classe simple résultat de l'opération de serveur qui est également utilisée en interne pour de nombreuses fonctions. P>
#define RETURN_IF_FAILED(call) \ { \ OpResult result = call; \ if (result.failed()) \ return result; \ }
8 Réponses :
C'est un compromis. Vous négociez une taille de code pour l'obfuscation de la logique. Je préfère préserver la logique comme visible. P>
Je n'aime pas les macros de ce type parce qu'ils brisent Intellisense (sous Windows) et débogage de la logique du programme. Essayez de mettre un point d'arrêt sur les énoncés 10 La pire chose à ce sujet est qu'une fois que vous avez accepté cela, il est difficile de discuter contre les macros monstres de 30 lignes que certains programmeurs aiment utiliser pour des mini-tâches communément observées, car elles «clarifient les choses». J'ai vu du code dans lequel différents types d'exception ont été traités de cette manière par quatre macros en cascade, ce qui entraîne 4 lignes dans le fichier source, avec les macros en expansion pour> 100 lignes réelles. Maintenant, vous réduisez votre code de code? Non, il est impossible de raconter facilement avec des macros. P>
Un autre argument général contre les macros, même s'il n'est pas manifestement applicable ici, est la capacité de les nichier de manière difficile à déchiffrer des résultats ou de transmettre des arguments qui entraînent des arguments étranges mais compilables. L'utilisation de Edit: Un commentaire Je devrais ajouter est que si vous répétez vraiment cette erreur, la logique de vérification des erreurs, peut-être, il existe peut-être des opportunités de refactorisation dans le code. Pas une garantie, mais une meilleure façon de réduire de code de codes si elle s'applique. Recherchez des séquences répétées d'appels et encapsulez des séquences communes dans leur propre fonction, plutôt que de répondre à la manière dont chaque appel est manipulé isolément. P> Retour code> dans votre fonction - non pas le chèque, juste le
retour code>. Essayez de passer à travers le code qui est dans la macro. P>
++ x code> dans une macros qui utilise l'argument deux fois. Je sais toujours où je me tiens au code et je ne peux pas dire ça sur une macro. P>
Je conviens que la macro devrait toujours être la dernière chose à utiliser, lorsque tous les autres moyens de «clarifier les choses» ont été jugés, et cela devrait être simple, mais c'est vraiment préférable de copyplasta la macro TheWher au lieu de son utilisation?
Qu'il augmente le code de code de code ou ne dépend pas de savoir s'il existe ou non une alternative à ces macros. Si l'alternative aux macros consiste à écrire manuellement les 100 lignes, les macros ne augmentent pas le code de code. S'il y a une alternative, les macros sont discutables.
@Peter - En désaccord avec respect. Je ne mettrais jamais que de nombreuses lignes de code dans une macro pour le code de production. Le code de test est une autre chose. Il est littéralement impossible de déboguer ce code et lorsque la vraie nature du code est cachée à une telle degré, c'est une odeur de code quel que soit le mécanisme d'obscurcissement.
En fait, je préfère légèrement autre solution. La chose est que le résultat de l'appel intérieur n'est pas nécessairement un résultat valide d'un appel externe. Par exemple, une défaillance interne peut être "Fichier introuvable", mais la "configuration non disponible" extérieure ". Par conséquent, ma suggestion est de recréer le Techniquement, dans mon cas, la macro ressemble à p> cette solution nécessite toutefois une gestion de la mémoire, etc. P> Un certain puriste affirmant qu'aucun rendement explicite entrave la lisibilité du code. À mon avis, avoir explicitement code> retour code> dans la partie du nom de la macro suffit à empêcher la confusion pour tout développeur qualifié et attentionné. P> Mon avis est que de telles macros Don 't obscurcir la logique du programme, mais au contraire le rendre plus propre. Avec une telle macro, vous déclarez votre intention de manière claire et concise, tandis que l'inverse de l'autre sens semble être trop verbeuse et donc une erreur d'erreur. Faire l'analyse des Mainteniers d'analyser la même construction Une approche alternative sans retour précoce s'applique à chaque ligne de code Le motif de type ayant un Popular < / em> besoin de faire vérifier les retours (ou tout) avec des macros semble être un léger signe de fonctionnalité de langue manquante pour moi. P> p> opresult code> (potentiellement emballer l'opresulte "intérieure" pour obtenir un meilleur débogage). Tout cela va à la direction de "InnErException" dans .NET.
opresult r = appel (); Si (R.Failed) Retour R CODE> Gasturez-vous de leur temps. P>
CochedCall (r, appel) < / code> avec
#define checkedCall (r, appelez) do {if (r.sucédé) r = appel; } tandis que (faux) code>. Ceci est dans mes yeux beaucoup moins pire et définitivement surmonté, car les gens ont tendance à oublier l'ajout de
checkedCall () code> lors de l'ajout de plus de code. P>
Quelque chose de similaire pourrait être aussi utile.
Si vous en avez besoin, mettez ces appels internes dans leurs propres fonctions (inlined) avec une fonction extérieure interprétant leurs résultats. Ensuite, il n'y a pas besoin de ce piratage macro.
@SBI: Mon code dans la réponse est juste un indice. Le code de production réel utilise certaines fonctions d'assistance appropriées.
Tant que la définition macro est assise dans un fichier de mise en œuvre et n'est pas défini dès que cela n'est pas nécessaire, je ne serais pas horrifié em>. Cependant, je n'utiliserait que cela après avoir exclu toutes les solutions non macro. p> p>
Je suis d'accord avec Steve's POV .
Je pensais d'abord, au moins réduisez le macro à p> mais il est arrivé à moi déjà est em> un one-liner, donc Il y a vraiment peu d'avantages dans la macro. P> Je pense, essentiellement, vous devez faire un compromis entre la capacité d'écriture et la lisibilité. La macro est définitivement plus facile à écrire em> strong>. C'est cependant une question ouverte si elle est également plus facile à lue em> forte>. Ce dernier est un jugement subjectif à faire. Néanmoins, en utilisant des macros objectivement les em> obfusque code. P> En fin de compte, le problème sous-jacent est que vous ne devez pas utiliser des exceptions. Vous n'avez pas dit quelles sont les raisons de cette décision, mais j'espère sûrement qu'ils valent les problèmes de cette cause. p> p>
De cette façon, vous devez appeler la fonction, puis la macro, ainsi que vous devez également utiliser un bloc partout, ou être prudent pour ne pas faire de variables de résultat en double.
La macro de votre exemple n'est pas optimale, car elle apporterait une erreur dans le code comme si (cond) retour_if_failed (...) sinon do_something_else; code>. Vous voudriez peut-être ajouter l'habituel
do {...} alors que (0) code> autour de.
@Vlad: Je discutais i> contre B> cette macro, i> C'est pourquoi je n'ai pas réfléchi.
@Marwin: Vous n'avez pas besoin d'être des précautions, car le compilateur l'attrapera si vous échouez.
pourrait être fait avec C ++ 0x Lambdas.
template<typename F> inline OpResult if_failed(OpResult a, F f) { if (a.failed()) return a; else return f(); }; OpResult something() { int mah_var = 0; OpResult x = do_something(); return if_failed(x, [&]() -> OpResult { std::cout << mah_var; return f; }); };
À mon avis, cachez une déclaration de retour dans une macro est une mauvaise idée. L'obfiducation de code '(j'aime ce terme ..!) Atteint le niveau le plus élevé possible. Ma solution habituelle à ces problèmes est d'agréger l'exécution de la fonction à un endroit et de contrôler le résultat de la manière suivante (en supposant que vous disposez de 5 fonctions nullaires):
std::array<std::function<OpResult ()>, 5> tFunctions = { f1, f2, f3, f4, f5 }; auto tFirstFailed = std::find_if(tFunctions.begin(), tFunctions.end(), [] (std::function<OpResult ()>& pFunc) -> bool { return pFunc().failed(); }); if (tFirstFailed != tFunctions.end()) { // tFirstFailed is the first function which failed... }
Il est difficile d'appeler cette cachette i> une déclaration de retour, lorsque le nom de la macro commence par retour_if _... code>
Y a-t-il des informations en résultat qui est en fait utile si l'appel échoue?
sinon, alors p> suffirait. p> p>
Après 10 ans, je vais répondre à ma propre question à ma satisfaction, si seulement j'avais une machine à remous ...
J'ai rencontré plusieurs fois de nombreuses reprises dans de nouveaux projets. Même lorsque des exceptions ont été autorisées, je ne veux pas toujours les utiliser pour "Échec normal". P>
J'ai finalement découvert un moyen d'écrire ce genre de déclarations. P>
pour le résultat générique Cela inclut le message, j'utilise ceci: p> et ensuite, j'ai une classe d'assistance spéciale dans ce formulaire (similaire pour d'autres types de retour) p> if (Failed result = trySomething())
showError(result.getMessage().str());
Et si un certain nettoyage est requis?
Eh bien, ma réponse acceptée a été supprimée unilatéralement par un modérateur aléatoire qui ne l'aime tout simplement pas.