Me doy cuenta de que si bien la pregunta no tiene una etiqueta de idioma, probablemente esté hablando implícitamente de "idiomas de café". Pero solo en aras de la exhaustividad, me gustaría mencionar el aparente consenso algo divergente en el mundo de C ++.
Hay tres cosas en las que los programadores de C ++ generalmente estarán interesados:
- ¿Tendrá cero gastos generales en compilaciones optimizadas? (Es decir, ¿se puede "compilar"?)
- ¿Puedo usarlo para atrapar a un depurador justo en el punto donde se detectó el error?
- ¿Puedo usarlo para informar problemas de funciones declaradas
noexcept?
En el pasado, me acerqué al primer problema escribiendo código como este
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;
}
donde CHECK_ARGSestá #defined una constante de tiempo de compilación para que el compilador pueda eliminar completamente todo el código de comprobación de argumentos en compilaciones optimizadas. (No digo que compilar los cheques sea algo bueno en general, pero creo que un usuario debería tener la opción de compilarlos).
Todavía me gusta de esta solución que el código de comprobación de argumentos sea claramente visible agrupado en el if. Sin embargo, el segundo y el tercer problema no se resuelven con esto. Por lo tanto, ahora me estoy inclinando nuevamente hacia el uso de una assertmacro para la verificación de argumentos.
Los estándares de codificación de Boost están de acuerdo con esto:
¿Qué pasa con los errores del programador?
Como desarrollador, si violé una condición previa de una biblioteca que estoy usando, no quiero que la pila se desenrolle. Lo que quiero es un volcado de núcleo o su equivalente, una forma de inspeccionar el estado del programa en el punto exacto donde se detectó el problema. Eso generalmente significa assert()o algo así.
Hubo una charla muy interesante dada por John Lakos en CppCon'14 titulada Programación defensiva bien hecha ( parte 1 , parte 2 ). En la primera parte de su charla, analiza la teoría de los contratos y el comportamiento indefinido. En la segunda parte, presenta lo que considero una muy buena propuesta para la verificación sistemática de argumentos. En esencia, propone macros de afirmación que permiten al usuario seleccionar cuánto presupuesto (en términos de utilización de la CPU) está dispuesto a donar a la biblioteca para la verificación de argumentos y hace que la biblioteca haga un uso racional de ese presupuesto. Además, el usuario también puede instalar una función global de manejo de errores que se llamará en caso de que se detecte un contrato roto.
Con respecto al aspecto de que una función es privada, no creo que esto signifique que nunca deberíamos hacer que verifique sus argumentos. Podemos confiar más en nuestro propio código para no violar el contrato de una función interna, pero también sabemos que tampoco somos perfectos. La comprobación de argumentos en las funciones internas es tan útil para detectar nuestros propios errores como lo es en las funciones públicas para detectar errores en el código del cliente.