Good Practice
Good Practice
CAPÍTULO 0
---------
0.2: Las mejores prácticas son cosas que deberías hacer, porque de esa forma
se considera generalmente un estándar o muy recomendable. Es decir, o todo
el mundo lo hace así (y si lo haces de otro modo, estarás haciendo algo que
la gente no espera), o es superior a las alternativas.
0.7: Cree un nuevo proyecto para cada nuevo programa que escriba.
0.10: Desactive las extensiones del compilador para asegurarse de que sus
programas (y prácticas de codificación) siguen cumpliendo los estándares
de C++ y funcionarán en cualquier sistema.
0.11: No dejes que se acumulen los avisos. Resuélvelos a medida que los
encuentres (como si fueran errores).
De lo contrario, un aviso sobre un problema grave puede perderse entre
avisos sobre problemas no graves.
---------
CAPÍTULO 1
---------
1.5 Emite una nueva línea cada vez que se completa una línea de salida.
---------
CAPÍTULO 2
---------
2.3: No coloque una sentencia return al final de una función que no devuelva
valores.
2.5: Defina sus variables locales tan cerca de su primer uso como sea razonable.
Para maximizar la posibilidad de que los includes que faltan sean marcados
por el compilador, ordene sus #includes de la siguiente manera:
1. El archivo de cabecera emparejado
2. Otras cabeceras del proyecto
3. Cabeceras de bibliotecas de terceros
4. Cabeceras de bibliotecas estándar
Las cabeceras de cada grupo deben ordenarse alfabéticamente.
2.12: Prefiera los protectores de cabecera a #pragma una vez para obtener la
máxima portabilidad.
---------
CAPÍTULO 3
---------
3.10: Utilice una herramienta de análisis estático en sus programas para ayudar
a encontrar áreas en las que su código no cumple con las mejores prácticas.
---------
CAPÍTULO 4
---------
4.2: Utilice una lista de parámetros vacía en lugar de void para indicar que
una función no tiene parámetros.
4.3: Para lograr la máxima compatibilidad, no debe suponer que las variables
son mayores que el tamaño mínimo especificado.
4.4: Prefiera los tipos abreviados que no utilizan el sufijo int ni el prefijo
signed.
4.5: Prefiera los números con signo a los números sin signo para almacenar
cantidades (incluso cantidades que no deben ser negativas) y realizar
operaciones matemáticas. Evita mezclar números con y sin signo.
4.6: • Prefiera int cuando el tamaño del entero no importe (por ejemplo, el
número siempre cabrá dentro del rango de un entero con signo de 2 bytes).
Por ejemplo, si está pidiendo al usuario que introduzca su edad, o que
cuente del 1 al 10, no importa si int tiene 16 o 32 bits (los números
cabrán de cualquier forma). Esto cubrirá la gran mayoría de los casos con
los que probablemente te encuentres.
• Prefiera std::int#_t cuando almacene una cantidad que necesite un rango
garantizado.
• Prefiera std::uint#_t cuando manipule bits o cuando necesite un
comportamiento envolvente bien definido.
4.8: Asegúrate siempre de que el tipo de tus literales coincide con el tipo de
las variables a las que se asignan o que se utilizan para inicializar. De
lo contrario, se producirá una conversión innecesaria, posiblemente con
pérdida de precisión.
4.11: Ponga los caracteres independientes entre comillas simples (por ejemplo,
't' o '\n', no "t" o "\n"). Esto ayuda al compilador a optimizar de forma
más eficaz.
4.13: Coloque const antes del tipo (porque es más idiomático hacerlo).
---------
CAPÍTULO 5
---------
5.1: Utilice paréntesis para dejar claro cómo debe evaluarse una expresión no
trivial (aunque sean técnicamente innecesarios).
5.7: Si se pretende que NOT lógico opere sobre el resultado de otros operadores,
los otros operadores y sus operandos deben ir entre paréntesis.
---------
CAPÍTULO O
---------
O.1: La manipulación de bits es una de las pocas ocasiones en las que debe
utilizar sin ambigüedad enteros sin signo (o std::bitset).
O.2: Para evitar sorpresas, utilice los operadores bitwise con operandos sin
signo o std::bitset.
---------
CAPÍTULO 6
---------
6.3: Defina las variables en el ámbito más limitado posible. Evita crear nuevos
bloques cuyo único propósito sea limitar el ámbito de las variables.
6.8: Utilice variables locales en lugar de globales siempre que sea posible.
6.10: Inicialice sus variables locales estáticas. Las variables locales estáticas
sólo se inicializan la primera vez que se ejecuta el código, no en
llamadas posteriores.
6.12: Prefiera los espacios de nombres explícitos a las sentencias using. Evite
el uso de directivas siempre que sea posible. Las declaraciones de uso
pueden utilizarse dentro de bloques.
Evite el uso de la palabra clave inline para funciones a menos que tenga
una razón específica y convincente para hacerlo.
6.14: Utilice un tipo de retorno constexpr para las funciones que necesitan
devolver una constante en tiempo de compilación.
---------
CAPÍTULO 7
---------
7.4: Prefiera las sentencias switch a las cadenas if-else cuando haya que elegir.
Coloque el caso por defecto en último lugar en el bloque de conmutación.
7.5: Utilice el atributo [[fallthrough]] (junto con una sentencia null) para
indicar un fallthrough intencionado.
7.6: Evite las sentencias goto (a menos que las alternativas sean
significativamente peores para la legibilidad del código).
Prefiera los bucles for a los bucles while cuando haya una variable de
bucle obvia.
Prefiera los bucles while a los bucles for cuando no haya una variable de
bucle obvia.
7.11: Sólo use un halt si no hay una forma segura de retornar normalmente desde
la función principal. Si no has deshabilitado las excepciones, prefiere
usar excepciones para manejar errores de forma segura.
7.12: Escriba su programa en unidades pequeñas y bien definidas (funciones o
clases), compile a menudo y pruebe su código sobre la marcha.
7.17: Utilice aserciones para documentar casos que deberían ser lógicamente
imposibles.
7.19: Utiliza std::random_device para sembrar tus PRNGs (a menos que no esté
implementado correctamente para tu compilador/arquitectura de destino).
---------
CAPÍTULO 8
---------
8.3: Evite las conversiones estrechas siempre que sea posible. Si necesita
realizar una, utilice static_cast para que sea una conversión explícita.
8.6: Nombra tus alias de tipo empezando con mayúscula y no utilices un sufijo
(a menos que tengas una razón específica para hacer lo contrario).
Utilice los alias de tipos con sensatez, cuando supongan una clara ventaja
para la legibilidad o el mantenimiento del código.
8.7: Utilice la deducción de tipo para sus variables, a menos que necesite
comprometerse con un tipo específico.
8.8: Favorecer los tipos de retorno explícitos frente a la deducción de tipos
de retorno de función para funciones normales.
8.13: Utilice una sola letra mayúscula (empezando por T) para nombrar sus tipos
de plantilla (por ejemplo, T, U, V, etc...)
---------
CAPÍTULO 9
---------
9.3: Al definir una referencia, coloque el signo ampersand junto al tipo (no
junto al nombre de la variable de referencia).
9.4: Favorece las referencias lvalue a const sobre las referencias lvalue a
non-const a menos que necesites modificar el objeto referenciado.
9.5: Favorezca el paso por referencia const sobre el paso por referencia
no-const a menos que tenga una razón específica para hacer lo contrario
(por ejemplo, la función necesita cambiar el valor de un argumento).
Prefiera el paso por valor para los objetos que son baratos de copiar, y
el paso por referencia constante para los objetos que son caros de copiar.
Si no estás seguro de si un objeto es barato o caro de copiar, prefiere
pasar por referencia const.
9.7: Valore inicializar sus punteros (para que sean punteros nulos) si no los
está inicializando con la dirección de un objeto válido.
9.9: Prefiera el paso por referencia al paso por dirección a menos que tenga
una razón específica para utilizar el paso por dirección.
---------
CAPÍTULO 10
---------
10.1: Denomine los tipos definidos por el programa empezando por mayúscula y
sin sufijo.
Un tipo definido por el programa utilizado en un solo archivo de código
debe definirse en ese archivo de código lo más cerca posible del primer
punto de uso.
10.3: Evite asignar valores explícitos a sus enumeradores a menos que tenga una
razón de peso para hacerlo.
10.4: Favorezca las enumeraciones con alcance sobre las enumeraciones sin alcance
a menos que haya una razón de peso para hacer lo contrario.
10.6: Prefiera la forma de lista con corchetes (no copia) al inicializar agregados.
10.7: Proporcione un valor por defecto para todos los miembros. Esto asegura que
sus miembros serán inicializados incluso si la definición de la variable
no incluye una lista de inicializadores.
---------
CAPÍTULO 11
---------
11.8: Favorece la sintaxis de puntero (*) sobre la sintaxis de matriz ([]) para
parámetros de función de matriz.
11.11: Establece los punteros eliminados a nullptr a menos que salgan del ámbito
inmediatamente después.
---------
CAPÍTULO 12
---------
Intente evitar las lambdas mutables. Las lambdas no mutables son más
fáciles de entender y no sufren los problemas anteriores, así como otros
más peligrosos que surgen cuando se añade la ejecución paralela.
---------
CAPÍTULO 13
---------
Utilice la palabra clave struct para las estructuras que sólo contienen datos.
Utilice la palabra clave class para objetos que tengan tanto datos como funciones.
13.3: Haz que las variables miembro sean privadas y las funciones miembro
públicas, a menos que tengas una buena razón para no hacerlo.
13.12: Haga que cualquier función miembro que no modifique el estado del objeto
de la clase sea const, para que pueda ser llamada por objetos const.
13.13: Acceda a los miembros estáticos por el nombre de la clase (utilizando el
operador de resolución de ámbito) en lugar de a través de un objeto de la
clase (utilizando el operador de selección de miembros).
---------
CAPÍTULO 14
---------
---------
CAPÍTULO 16
---------
16.3: Implemente el tipo de relación más sencillo que satisfaga las necesidades
de su programa, no lo que parezca correcto en la vida real.
---------
CAPÍTULO 17
---------
17.9: Evite la herencia múltiple a menos que las alternativas conduzcan a una
mayor complejidad.
---------
CAPÍTULO 18
---------
18.3: Utilice la palabra clave virtual en las funciones virtuales de una clase base.
Utilice el especificador override (pero no la palabra clave virtual) en
funciones override en clases derivadas.