Je me rends compte que même si la question n'a pas de balise de langue, il s'agit probablement implicitement de «langues du café». Mais juste pour être complet, je voudrais mentionner le consensus apparent quelque peu divergent dans le monde C ++.
Les programmeurs C ++ sont généralement intéressés par trois choses:
- Aura-t-il zéro frais généraux dans les versions optimisées? (Autrement dit, peut-il être «compilé»?)
- Puis-je l'utiliser pour intercepter un débogueur juste au point où l'erreur a été détectée?
- Puis-je l'utiliser pour signaler des problèmes à partir des fonctions déclarées
noexcept
?
Dans le passé, j'ai abordé le premier problème en écrivant du code comme celui-ci
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
où CHECK_ARGS
est #define
d à une constante de temps de compilation afin que le compilateur puisse éliminer complètement tout le code de vérification des arguments dans les builds optimisées. (Je ne dis pas que la compilation des vérifications est une bonne chose en général, mais je crois qu'un utilisateur devrait avoir la possibilité de les compiler.)
J'aime toujours dans cette solution que l'argument vérifiant le code soit clairement visible, regroupé dans le if
. Cependant, les deuxième et troisième problèmes ne sont pas résolus par cela. Par conséquent, je penche maintenant davantage vers l'utilisation d'une assert
macro pour la vérification des arguments.
Les normes de codage Boost sont d'accord avec ceci:
Qu'en est-il des erreurs du programmeur?
En tant que développeur, si j'ai violé une condition préalable d'une bibliothèque que j'utilise, je ne veux pas que la pile se déroule. Ce que je veux, c'est un vidage de mémoire ou l'équivalent - un moyen d'inspecter l'état du programme au point exact où le problème a été détecté. Cela signifie généralement assert()
ou quelque chose comme ça.
Il y a eu une conférence très intéressante donnée par John Lakos à CppCon'14 intitulée Programmation défensive bien faite ( partie 1 , partie 2 ). Dans la première partie de son intervention, il aborde la théorie des contrats et des comportements indéfinis. Dans la deuxième partie, il présente ce que je considère comme une très bonne proposition de vérification systématique des arguments. En substance, il propose des macros d'assertion qui permettent à l'utilisateur de sélectionner la part du budget (en termes d'utilisation du processeur) qu'il est prêt à donner à la bibliothèque pour la vérification des arguments et à la bibliothèque d'utiliser judicieusement ce budget. En outre, l'utilisateur peut également installer une fonction globale de gestion des erreurs qui sera appelée en cas de détection d'un contrat rompu.
En ce qui concerne l'aspect qu'une fonction est privée, je ne pense pas que cela signifie que nous ne devrions jamais la faire vérifier ses arguments. Nous pouvons faire davantage confiance à notre propre code pour ne pas violer le contrat d'une fonction interne, mais nous savons également que nous ne sommes pas parfaits non plus. La vérification des arguments dans les fonctions internes est tout aussi utile pour détecter nos propres bogues que pour les fonctions publiques pour détecter les bogues dans le code client.