Devrait-il y avoir des assertions dans les versions

20

Le comportement par défaut de assertC ++ est de ne rien faire dans les versions. Je suppose que cela est fait pour des raisons de performances et peut-être pour empêcher les utilisateurs de voir des messages d'erreur désagréables.

Cependant, je dirais que les situations où un assertaurait déclenché mais aurait été désactivé sont encore plus gênantes car l'application se bloquerait probablement de manière encore pire sur la ligne car un invariant a été cassé.

De plus, l'argument de performance pour moi ne compte que lorsqu'il s'agit d'un problème mesurable. La plupart des asserts dans mon code ne sont pas beaucoup plus complexes que

assert(ptr != nullptr);

ce qui aura un faible impact sur la plupart du code.

Cela m'amène à la question: les assertions (c'est-à-dire le concept, pas l'implémentation spécifique) doivent-elles être actives dans les versions de versions? Pourquoi pas)?

Veuillez noter que cette question ne concerne pas la façon d'activer les assertions dans les versions de version (comme #undef _NDEBUGou en utilisant une implémentation d'assertion auto-définie). De plus, il ne s'agit pas d'activer des assertions dans du code de bibliothèque tiers / standard mais dans du code que je contrôle.

Personne
la source
Je connais un acteur mondial du marché de la santé qui a installé une version de débogage de son système d'information hospitalier sur les sites clients. Ils avaient également un accord spécial avec Microsoft pour y installer les bibliothèques de débogage C ++. Eh bien, la qualité de leur produit était ...
Bernhard Hiller
2
Il y a un vieux dicton qui dit que "retirer des assertions, c'est un peu comme porter un gilet de sauvetage pour pratiquer dans le port, mais laisser les gilets de sauvetage derrière quand votre navire part pour l'océan" ( wiki.c2.com/?AssertionsAsDefensiveProgramming ) . Personnellement, je les garde activés dans les versions par défaut. Malheureusement, cette pratique n'est pas très courante dans le monde C ++, mais au moins le vétéran de renom C ++ James Kanze a toujours plaidé en faveur du maintien des assertions dans les versions de versions: stackoverflow.com/a/12162195/3313064
Christian Hackl

Réponses:

20

Le classique assertest un outil de l'ancienne bibliothèque C standard, pas de C ++. Il est toujours disponible en C ++, au moins pour des raisons de rétrocompatibilité.

Je n'ai pas de chronologie précise des bibliothèques standard C à portée de main, mais je suis presque sûr qu'elles assertétaient disponibles peu de temps après la mise en service de K&R C (vers 1978). En C classique, pour écrire des programmes robustes, l'ajout de tests de pointeur NULL et la vérification des limites du tableau doivent être effectués plus fréquemment qu'en C ++. Le brut des tests de pointeur NULL peut être évité en utilisant des références et / ou des pointeurs intelligents au lieu de pointeurs, et en utilisant std::vector, la vérification des limites du tableau est souvent inutile. De plus, la performance atteinte en 1980 était nettement plus importante qu'aujourd'hui. Je pense donc que c'est très probablement la raison pour laquelle "assert" a été conçu pour être actif uniquement dans les versions de débogage par défaut.

De plus, pour une gestion réelle des erreurs dans le code de production, une fonction qui teste simplement une condition ou un invariant, et plante le programme si la condition n'est pas remplie, n'est dans la plupart des cas pas assez flexible. Pour le débogage, c'est probablement correct, car celui qui exécute le programme et observe l'erreur a généralement un débogueur à portée de main pour analyser ce qui se passe. Pour le code de production, cependant, une solution sensée doit être une fonction ou un mécanisme qui

  • teste une condition (et arrête l'exécution à la portée où la condition échoue)

  • fournit un message d'erreur clair si la condition ne tient pas

  • permet à la portée externe de prendre le message d'erreur et de le transmettre à un canal de communication spécifique. Ce canal peut être quelque chose comme stderr, un fichier journal standard, une boîte de message dans un programme GUI, un rappel général de gestion des erreurs, un canal d'erreur activé par le réseau ou tout ce qui convient le mieux à un logiciel particulier.

  • permet à la portée externe au cas par cas de décider si le programme doit se terminer correctement ou s'il doit continuer.

(Bien sûr, il existe également des situations où la fermeture immédiate du programme en cas de condition non remplie est la seule option raisonnable, mais dans de tels cas, cela devrait également se produire dans une version de génération, pas seulement dans une version de débogage).

Étant donné que le classique assertne fournit pas ces fonctionnalités, ce n'est pas un bon choix pour une version de version, en supposant que la version de version est ce que l'on déploie en production.

Vous pouvez maintenant vous demander pourquoi il n'y a pas une telle fonction ou mécanisme dans la bibliothèque standard C qui offre ce type de flexibilité. En fait, en C ++, il existe un mécanisme standard qui a toutes ces fonctionnalités (et plus), et vous le savez: il s'appelle des exceptions .

En C, cependant, il est difficile de mettre en œuvre un bon mécanisme standard à usage général pour la gestion des erreurs avec toutes les fonctionnalités mentionnées en raison de l'absence d'exceptions dans le cadre du langage de programmation. Ainsi, la plupart des programmes C ont leurs propres mécanismes de gestion des erreurs avec des codes de retour, ou "goto", ou "sauts longs", ou un mélange de cela. Ce sont souvent des solutions pragmatiques qui s’adaptent au type particulier de programme, mais ne sont pas «suffisamment polyvalentes» pour s’intégrer à la bibliothèque standard C.

Doc Brown
la source
Ah, totalement oublié l'héritage C (après tout son #include <cassert>). Cela a tout à fait du sens maintenant.
Personne le
1
Je suis totalement en désaccord avec toute cette réponse. Lancer une exception lorsque votre application a découvert que son code source était bogué est le dernier recours dans des langages comme Java qui ne peuvent pas faire mieux, mais en C ++, arrêtez le programme immédiatement dans une telle situation. Vous ne voulez pas pile déroulage pour provoquer des opérations supplémentaires à exécuter à ce moment - là. Un programme buggy peut écrire des données éventuellement corrompues dans des fichiers, des bases de données ou des sockets réseau. Il suffit de planter dès que possible (et éventuellement de redémarrer le processus par un mécanisme externe).
Christian Hackl
1
@ChristianHackl: Je suis d'accord qu'il y a des situations où la fin d'un programme est la seule option viable, mais cela devrait également se produire en mode de libération, et assertc'est aussi le mauvais outil pour cela (le fait de lever une exception peut en effet être également la mauvaise réaction ). Cependant, je suis pratiquement sûr qu'en réalité, il asserta également été utilisé pour de nombreux tests en C, où en C ++, on utiliserait des exceptions aujourd'hui.
Doc Brown du
15

Si vous souhaitez que les assertions soient activées dans une version, vous avez demandé à asserts de faire le mauvais travail.

Le point des assertions est qu'elles ne sont pas activées dans une version. Cela permet de tester des invariants pendant le développement avec du code qui autrement devrait être du code d'échafaudage. Code qui doit être supprimé avant la publication.

Si vous pensez que quelque chose devrait être testé même pendant la publication, écrivez du code qui le teste. La If throwconstruction fonctionne très bien. Si vous souhaitez dire quelque chose de différent des autres lancers, utilisez simplement une exception descriptive qui dit ce que vous souhaitez dire.

Ce n'est pas que vous ne pouvez pas changer la façon dont vous utilisez les assertions. C'est que cela ne vous apporte rien d'utile, va à l'encontre des attentes et ne vous laisse aucun moyen propre de faire ce que les affirmations étaient censées faire. Ajoutez des tests inactifs dans une version.

Je ne parle pas d'une implémentation spécifique de l'assert mais du concept d'une assertion. Je ne veux pas abuser d'affirmer ou de confondre les lecteurs. Je voulais d'abord demander pourquoi il en est ainsi. Pourquoi n'y a-t-il pas de release_assert supplémentaire? N'est-ce pas nécessaire? Quelle est la raison d'être de l'assertion de la désactivation lors de la libération? - Personne

Pourquoi pas relase_assert? Franchement parce que les assertions ne sont pas assez bonnes pour la production. Oui, il y a un besoin, mais rien ne répond bien à ce besoin. Oh, bien sûr, vous pouvez concevoir le vôtre. Mécaniquement, votre fonction throwIf a juste besoin d'un bool et d'une exception à lancer. Et cela peut répondre à vos besoins. Mais vous limitez vraiment le design. C'est pourquoi cela ne me surprend pas qu'il n'y ait pas de système de levée d'exception comme une exception dans votre bibliothèque de langues. Ce n'est certainement pas que vous ne pouvez pas le faire. . Si nous avions eu un système de release_assert en conserve qui ne répondait pas à nos besoins, je pense qu'il aurait fait plus de mal que de bien. Vous demandez une bonne abstraction qui signifierait que vous n'auriez pas à penser à ce problème. J'en veux un aussi mais il ne semble pas que nous y soyons encore.D'autres l'ont fait . Mais faire face au cas où les choses tournent mal représente 80% du travail pour la plupart des programmes. Et jusqu'à présent, personne ne nous a montré une bonne solution universelle. Traiter efficacement ces cas peut devenir compliqué

Pourquoi les assertions sont-elles désactivées dans la version? Les assertions ont été créées au plus fort de l'ère du code d'échafaudage. Code que nous avons dû supprimer car nous savions que nous ne le voulions pas en production, mais nous savions que nous voulions l'exécuter en développement pour nous aider à trouver des bogues. Les assertions étaient une alternative plus propre au if (DEBUG)modèle qui nous permettait de laisser le code mais de le désactiver. C'était avant le décollage des tests unitaires comme principal moyen de séparer le code de test du code de production. Les assertions sont encore utilisées aujourd'hui, même par des testeurs unitaires experts, à la fois pour clarifier les attentes et pour couvrir les cas où ils font encore mieux que les tests unitaires.

Pourquoi ne pas simplement laisser le code de débogage en production? Parce que le code de production ne doit pas embarrasser l'entreprise, ne pas formater le disque dur, ne pas corrompre la base de données et ne pas envoyer de courriels menaçants au président. En bref, c'est agréable de pouvoir écrire du code de débogage dans un endroit sûr où vous n'avez pas à vous en soucier.

candied_orange
la source
2
Je suppose que ma question est: pourquoi ce code doit-il être supprimé avant sa sortie? Les vérifications ne sont pas vraiment une perte de performance et si elles échouent, il y a certainement un problème sur lequel je préférerais un message d'erreur plus direct. Quel avantage offre l'utilisation d'une exception au lieu d'une assertion? Je ne voudrais probablement pas que du code sans rapport puisse le faire catch(...).
Personne le
2
@Nobody Le plus grand avantage de ne pas utiliser d'assertions pour des besoins non assertifs n'est pas de confondre vos lecteurs. Si vous ne voulez pas que le code soit désactivé, n'utilisez pas d'expressions idiomatiques qui indiquent qu'il le sera. C'est aussi mauvais que d'utiliser if (DEBUG)pour contrôler autre chose que le débogage du code. La micro optimisation peut ne rien signifier dans votre cas. Mais l'idiome ne doit pas être renversé simplement parce que vous n'en avez pas besoin.
candied_orange
Je pense que je n'ai pas clairement exprimé mon intention. Je ne parle pas d'une implémentation spécifique assertmais du concept d'une assertion. Je ne veux pas abuser assertou confondre les lecteurs. Je voulais d'abord demander pourquoi il en est ainsi. Pourquoi n'y a-t-il pas de supplément release_assert? N'est-ce pas nécessaire? Quelle est la justification de l'affirmation d'être désactivé lors de la libération?
Personne le
2
You're asking for a good abstraction.Je ne suis pas sûre à propos de ça. Je veux principalement traiter des problèmes où il n'y a pas de reprise et cela ne devrait jamais se produire. Prenez cela avec Because production code needs to [...] not format the hard drive [...]et je dirais que dans les cas où les invariants sont brisés, je prendrais une assertion en libération sur UB à tout moment.
Personne le
1
@Personne "les problèmes où il n'y a pas de récupération" peuvent être traités en lançant des exceptions et en ne les interceptant pas. Vous pouvez noter qu'ils ne devraient jamais se produire dans le texte du message de l'exception.
candied_orange
4

Les assertions sont un outil de débogage , pas une technique de programmation défensive. Si vous souhaitez effectuer la validation en toutes circonstances, effectuez la validation en écrivant un conditionnel - ou créez votre propre macro pour réduire le passe-partout.

amon
la source
4

assertest une forme de documentation, comme des commentaires. Comme les commentaires, vous ne les expédieriez pas normalement aux clients - ils n'appartiennent pas au code de version.

Mais le problème avec les commentaires est qu'ils peuvent devenir obsolètes, et pourtant ils sont conservés. C'est pourquoi les assertions sont bonnes - elles sont vérifiées en mode débogage. Lorsque l'assertion devient obsolète, vous la découvrez rapidement et saurez toujours comment corriger l'assertion. Ce commentaire devenu obsolète il y a 3 ans? Quiconque pense.

MSalters
la source
1
Donc, abandonner un invariant défaillant avant que quelque chose ne se passe n'est pas un cas d'utilisation valable?
Personne le
3

Si vous ne voulez pas qu'une "assertion" soit désactivée, n'hésitez pas à écrire une fonction simple qui a un effet similaire:

void fail_if(bool b) {if(!b) std::abort();}

C'est, assertest pour les tests où vous ne les voulez aller loin dans le produit livré. Si vous voulez que ce test fasse partie du comportement défini du programme, ce assertn'est pas le bon outil.

Nicol Bolas
la source
1
J'en suis bien conscient. La question est plutôt de savoir pourquoi la valeur par défaut est telle qu'elle est.
Personne le
3

Il est inutile de discuter de ce que l'assertion devrait faire, elle fait ce qu'elle fait. Si vous voulez quelque chose de différent, écrivez votre propre fonction. Par exemple, j'ai Assert qui s'arrête dans le débogueur ou ne fait rien, j'ai AssertFatal qui plantera l'application, j'ai des fonctions booléennes Assertion et AssertionFailed qui assert et retournent le résultat afin que je puisse à la fois affirmer et gérer la situation.

Pour tout problème inattendu, vous devez décider quel est le meilleur moyen pour le développeur et l'utilisateur de le gérer.

gnasher729
la source
Je n'avais pas l'intention de discuter de ce que l'assertion devrait faire. Ma motivation pour cette question était de trouver le raisonnement derrière les assertions qui ne sont pas dans la build de la version parce que je suis sur le point d'écrire le mien et que je souhaite collecter des informations sur les cas d'utilisation, les attentes et les pièges.
Personne le
Hm, ne serait-ce pas verify(cond)la façon normale d'affirmer et de renvoyer le résultat?
Déduplicateur
1
Je code en Ruby, pas en C, mais je ne suis pas d'accord avec la plupart des réponses ci-dessus, car arrêter le programme avec l'impression d'une trace fonctionne bien pour moi en tant que technique de programmation défensive ....... mon commentaire ne correspondait pas au taille maximale des commentaires en caractères, j'ai donc écrit une autre réponse ci-dessous.
Nakilon
2

Comme d'autres l'ont souligné, assertc'est en quelque sorte votre dernier bastion de défense contre les erreurs de programmation qui ne devraient jamais se produire. Ce sont des contrôles de santé mentale qui, espérons-le, ne devraient pas échouer à gauche et à droite au moment de l'expédition.

Il est également conçu pour être omis des versions stables, pour toutes les raisons que les développeurs pourraient trouver utiles: l'esthétique, les performances, tout ce qu'ils veulent. Cela fait partie de ce qui sépare une version de débogage d'une version de version, et par définition une version de version est dépourvue de telles affirmations. Il y a donc une subversion de la conception si vous voulez libérer la "version de version avec des assertions en place" analogique qui serait une tentative de version avec une _DEBUGdéfinition de préprocesseur et aucune NDEBUGdéfinition; ce n'est plus vraiment une version.

La conception s'étend même dans la bibliothèque standard. A titre d'exemple très basique parmi les nombreux, beaucoup d'implémentations de std::vector::operator[]sera assertune vérification de bon sens pour vous assurer que vous n'êtes pas de vérifier le vecteur hors limites. Et la bibliothèque standard commencera à fonctionner beaucoup, bien pire si vous activez ces vérifications dans une version. Une référence d' vectorutilisationoperator[]et un ctor de remplissage avec de telles assertions incluses par rapport à un ancien tableau dynamique simple montrera souvent que le tableau dynamique est considérablement plus rapide jusqu'à ce que vous désactiviez de telles vérifications, de sorte qu'elles ont souvent un impact sur les performances de manière très, loin d'être triviale. Une vérification de pointeur nul ici et une vérification hors limites peuvent en fait devenir une dépense énorme si ces vérifications sont appliquées des millions de fois sur chaque trame dans les boucles critiques précédant le code aussi simple que de déréférencer un pointeur intelligent ou d'accéder à un tableau.

Vous souhaitez donc probablement un outil différent pour le travail et un outil qui n'est pas conçu pour être omis des versions de version si vous souhaitez des versions de version qui effectuent de tels contrôles d'intégrité dans des domaines clés. Le plus utile que je trouve personnellement est la journalisation. Dans ce cas, lorsqu'un utilisateur signale un bogue, les choses deviennent beaucoup plus faciles s'il joignent un journal et la dernière ligne du journal me donne une grande idée de l'endroit où le bogue s'est produit et de ce qu'il pourrait être. Ensuite, en reproduisant leurs étapes dans une version de débogage, je pourrais également obtenir un échec d'assertion, et cet échec d'assertion me donne en outre d'énormes indices pour rationaliser mon temps. Pourtant, étant donné que la journalisation est relativement coûteuse, je ne l'utilise pas pour appliquer des contrôles d'intégrité extrêmement bas comme pour s'assurer qu'un tableau n'est pas accessible hors limites dans une structure de données générique.

Pourtant, enfin, et quelque peu en accord avec vous, je pourrais voir un cas raisonnable où vous pourriez réellement vouloir remettre aux testeurs quelque chose ressemblant à une version de débogage pendant les tests alpha, par exemple, avec un petit groupe de testeurs alpha qui, par exemple, ont signé un NDA . Là, cela pourrait rationaliser les tests alpha si vous remettez à vos testeurs autre chose qu'une version complète avec des informations de débogage attachées ainsi que des fonctionnalités de débogage / développement comme des tests qu'ils peuvent exécuter et une sortie plus détaillée pendant qu'ils exécutent le logiciel. J'ai au moins vu quelques grandes sociétés de jeu faire des choses comme ça pour alpha. Mais c'est pour quelque chose comme alpha ou des tests internes où vous essayez vraiment de donner aux testeurs autre chose qu'une version. Si vous essayez de livrer une version, alors par définition, elle ne devrait pas avoir_DEBUG défini ou bien qui est vraiment confondre la différence entre une version "debug" et "release".

Pourquoi ce code doit-il être supprimé avant sa sortie? Les vérifications ne sont pas vraiment une perte de performance et si elles échouent, il y a certainement un problème sur lequel je préférerais un message d'erreur plus direct.

Comme indiqué ci-dessus, les vérifications ne sont pas nécessairement triviales du point de vue des performances. Beaucoup sont probablement triviaux mais encore une fois, même la bibliothèque standard les utilise et cela pourrait affecter les performances de manière inacceptable pour de nombreuses personnes dans de nombreux cas si, disons, la traversée à accès aléatoire de std::vectorprenait 4 fois plus de temps dans ce qui est censé être une version optimisée en raison de sa vérification des limites qui n'est jamais censée échouer.

Dans une ancienne équipe, nous avons dû faire en sorte que notre bibliothèque de matrices et de vecteurs exclue certaines assertions dans certains chemins critiques juste pour accélérer les builds de débogage, car ces assertions ralentissaient les opérations mathématiques de plus d'un ordre de grandeur au point où elles se trouvaient. commencer à nous obliger à attendre 15 minutes avant que nous puissions même retracer dans le code d'intérêt. Mes collègues voulaient simplement supprimer leassertspurement et simplement parce qu'ils ont constaté que le simple fait de faire cela faisait une énorme différence. Au lieu de cela, nous nous sommes contentés de faire en sorte que les chemins de débogage critiques les évitent. Lorsque nous avons fait en sorte que ces chemins critiques utilisent directement les données vectorielles / matricielles sans passer par la vérification des limites, le temps nécessaire pour effectuer l'opération complète (qui comprenait plus que des calculs vectoriels / matriciels) a été réduit de quelques minutes à quelques secondes. C'est donc un cas extrême, mais les affirmations ne sont certainement pas toujours négligeables du point de vue des performances, pas même de près.

Mais c'est aussi juste la façon dont assertssont conçus. S'ils n'avaient pas un impact énorme sur les performances à tous les niveaux, je pourrais le préférer s'ils étaient conçus comme plus qu'une fonctionnalité de création de débogage ou si nous pouvions utiliser vector::atce qui inclut la vérification des limites même dans les versions et les sorties hors limites accès, par exemple (mais avec un énorme succès de performance). Mais actuellement, je trouve leur conception beaucoup plus utile, étant donné leur énorme impact sur les performances dans mes cas, en tant que fonctionnalité de débogage uniquement qui est omise lorsqu'elle NDEBUGest définie. Pour les cas avec lesquels j'ai travaillé au moins, cela fait une énorme différence pour une version de construction d'exclure les contrôles d'intégrité qui ne devraient jamais échouer en premier lieu.

vector::at contre. vector::operator[]

Je pense que la distinction de ces deux méthodes est au cœur de cela ainsi que l'alternative: les exceptions. vector::operator[]implémentations généralement assertpour s'assurer que l'accès hors limites déclenchera une erreur facilement reproductible lorsque vous tenterez d'accéder à un vecteur hors limites. Mais les implémenteurs de bibliothèque le font en supposant que cela ne coûtera pas un centime dans une version optimisée.

Pendant ce temps, il vector::atest fourni, qui effectue toujours les vérifications et les lancements hors limites, même dans les versions, mais il a une pénalité de performance au point où je vois souvent beaucoup plus de code vector::operator[]que vector::at. Une grande partie de la conception de C ++ fait écho à l'idée de «payer pour ce que vous utilisez / avez besoin», et beaucoup de gens préfèrent souvent operator[], ce qui ne dérange même pas avec les limites de l'archivage des versions, en se basant sur l'idée qu'elles ne pas besoin que les limites vérifient leurs versions optimisées. Soudain, si les assertions étaient activées dans les versions, les performances de ces deux seraient identiques et l'utilisation du vecteur finirait toujours par être plus lente qu'un tableau dynamique. Ainsi, une grande partie de la conception et des avantages des assertions est basée sur l'idée qu'elles deviennent gratuites dans une version.

release_assert

C'est intéressant après avoir découvert ces intentions. Naturellement, les cas d'utilisation de chacun seraient différents, mais je pense que je trouverais une utilisation pour un release_assertqui fait la vérification et plantera le logiciel affichant un numéro de ligne et un message d'erreur même dans les versions.

Ce serait pour certains cas obscurs dans mon cas où je ne veux pas que le logiciel récupère gracieusement comme il le ferait si une exception était levée. Je voudrais qu'il se bloque même dans la version dans ces cas afin que l'utilisateur puisse recevoir un numéro de ligne pour signaler quand le logiciel a rencontré quelque chose qui ne devrait jamais se produire, toujours dans le domaine des vérifications d'intégrité pour les erreurs de programmation, pas les erreurs d'entrée externes comme exceptions, mais assez bon marché pour être fait sans se soucier de son coût de sortie.

Il y a en fait certains cas où je trouverais un crash dur avec un numéro de ligne et un message d'erreur préférable à une récupération gracieuse d'une exception levée qui pourrait être assez bon marché pour être conservée dans une version. Et il y a des cas où il est impossible de récupérer à partir d'une exception, comme une erreur rencontrée en essayant de récupérer à partir d'une exception existante. Là, je trouverais un ajustement parfait pour un release_assert(!"This should never, ever happen! The software failed to fail!");et naturellement ce serait très bon marché car le contrôle serait effectué à l'intérieur d'un chemin exceptionnel en premier lieu et ne coûterait rien dans les chemins d'exécution normaux.


la source
Mon intention n'était pas d'activer les assertions dans un code tiers, voir la modification clarifiée. La citation de mon commentaire omet le contexte de ma question: Additionally, the performance argument for me only counts when it is a measurable problem.L'idée est donc de décider au cas par cas quand retirer une assertion de la libération.
Personne le
L'un des problèmes avec le dernier commentaire est que la bibliothèque standard utilise la même assertqui repose sur les mêmes _DEBUG/NDEBUGparamètres de préprocesseur que ceux que vous utiliseriez lorsque vous utilisez la assertmacro. Il n'y a donc aucun moyen d'activer sélectivement les assertions pour un seul morceau de code sans l'activer également pour la bibliothèque standard, par exemple, en supposant qu'il utilise la bibliothèque standard.
Un itérateur STL vérifie que vous pouvez désactiver séparément, ce qui désactive certaines des assertions, mais pas toutes.
C'est fondamentalement un outil grossier, pas granulaire, et toujours avec cette intention de conception d'être désactivé dans la version, donc vos coéquipiers pourraient l'utiliser dans des domaines critiques contre l'hypothèse que cela n'affectera pas les performances de la version, la bibliothèque standard l'utilise comme dans des domaines critiques, d'autres bibliothèques tierces l'utilisent de cette façon, etc. Et quand vous voulez quelque chose, vous pouvez désactiver / activer plus spécifiquement un morceau de code et non l'autre, nous sommes de retour à regarder autre chose que assert.
vector::operator[]et vector::at, par exemple, aurait pratiquement les mêmes performances si les assertions étaient activées dans les versions, et il n'y aurait aucun intérêt à les utiliser operator[]davantage du point de vue des performances, car ce serait de toute façon la vérification des limites.
2

Je code en Ruby, pas en C / C ++, et donc je ne parlerai pas de la différence entre les assertions et les exceptions mais je voudrais en parler comme d'une chose qui arrête le runtime . Je suis en désaccord avec la plupart des réponses ci-dessus, car arrêter le programme avec l'impression d'une trace fonctionne très bien pour moi en tant que technique de programmation défensive.
S'il existe un moyen d'appeler la routine (absolument peu importe la façon dont elle est écrite syntaxiquement et si le mot "assert" est utilisé ou existe dans le langage de programmation ou dsl) à appeler, cela signifie qu'un travail doit être effectué et le produit repasse immédiatement de la version «prête à l'emploi» à «nécessite un correctif» - maintenant, soit réécrivez-la dans la gestion des exceptions réelles, soit corrigez un bogue qui faisait apparaître des données erronées.

Je veux dire que Assert n'est pas une chose avec laquelle vous devriez vivre et appeler fréquemment - c'est un signal d'arrêt qui indique que vous devez faire quelque chose pour que cela ne se reproduise plus jamais. Et dire que "la build de la version ne devrait pas avoir d'assert", c'est comme dire "la build de la version ne devrait pas avoir de bogues" - mec, c'est presque impossible, faites-le.
Ou pensez-y comme à "l'échec des tests effectués et exécutés par l'utilisateur final". Vous ne pouvez pas prédire tout ce que l'utilisateur va faire avec votre programme, mais si un problème trop grave se passe mal, il devrait s'arrêter - c'est similaire à la façon dont vous construisez des pipelines de construction - vous arrêtez le processus et ne publiez pas, pensez-vous ? L'assertion force l'utilisateur à s'arrêter, à signaler et à attendre votre aide.

Nakilon
la source