Guía de estilo de C ++ de Google. Parte 2

Parte 1. Introducción

Parte 2. Archivos de encabezado

...





Al escribir código, todos usamos las reglas de formato de código. A veces se inventan reglas, en otros casos se utilizan guías de estilo prefabricadas. Aunque todos los programadores de C ++ leen inglés con más facilidad que los nativos, es mejor tener un manual en este último.

Este artículo es una traducción de parte de la guía de estilo C ++ de Google al ruso.

Artículo original (bifurcación en github), traducción actualizada .



Archivos de encabezado



Es deseable que cada archivo de origen .cc tenga un archivo de encabezado .h coincidente . También existen excepciones conocidas a esta regla, como pruebas unitarias o pequeños archivos .cc que contienen solo la función main () .



El uso correcto de los archivos de encabezado puede tener un gran impacto en la legibilidad, el tamaño y el rendimiento de su código.



Las siguientes reglas le ayudarán a evitar problemas frecuentes con los archivos de encabezado.



Archivos de encabezado independientes



Los archivos de encabezado deben ser autosuficientes (en términos de compilación) y tener la extensión .h . Otros archivos (sin encabezado) que se pretenden incluir en el código deben tener la extensión .inc y estar emparejados con el código de inclusión.



Todos los archivos de encabezado deben ser independientes. Los usuarios y las herramientas de desarrollo no deben depender de dependencias especiales al usar el archivo de encabezado. El archivo de encabezado debe poder bloquearse e incluir todos los archivos necesarios.



Es preferible colocar definiciones para plantillas y funciones en línea en el mismo archivo con sus declaraciones. Y estas definiciones deben incluirse en cada .ccarchivo utilizándolos, de lo contrario puede haber errores de enlace en algunas configuraciones de compilación. Si las declaraciones y definiciones están en archivos diferentes, una debe incluir la otra. No separe las definiciones en archivos de encabezado separados ( -inl.h ). Anteriormente, esta práctica era muy popular, ahora es indeseable.



Como excepción, si todas las variantes disponibles de los argumentos de la plantilla se crean a partir de la plantilla, o si la plantilla implementa la funcionalidad utilizada por una sola clase, entonces está permitido definir la plantilla en un archivo .cc (y solo uno) en el que se usa esta plantilla.



Hay situaciones raras en las que el archivo de encabezado no es autónomo. Esto puede suceder cuando un archivo se incluye en una ubicación no estándar, como en el medio de otro archivo. En este caso, es posible que no se vuelva a habilitar el bloqueo y que tampoco se incluyan archivos de encabezado adicionales. Nombre dichos archivos con la extensión .inc . Úselos en pares e intente cumplir los requisitos generales tanto como sea posible.



Reiniciar bloqueo



Todos los archivos de encabezado deben estar #define protegidos contra la reincorporación . El formato de definición de macro debe ser: <PROYECTO> _ <Ruta> _ <Archivo> _H_ .



Para garantizar la exclusividad, utilice los componentes de la ruta de archivo completa en el árbol del proyecto. Por ejemplo, el archivo foo / src / bar / baz.h en el proyecto foo puede tener el siguiente bloqueo:



#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif  // FOO_BAR_BAZ_H_


Anuncio preliminar



Si es posible, no utilice anuncios anticipados. # Incluya los archivos de encabezado requeridos en su lugar .



Definición

"Predeclaración" es una declaración de una clase, función, plantilla sin una definición correspondiente.



Por



  • . #include ( ) .
  • . #include - .




  • , .
  • API, . , API: , , .
  • std:: .
  • , : #include. , #include ( ) :



          // b.h:
          struct B {};
          struct D : B {};
          // good_user.cc:
          #include "b.h"
          void f(B*);
          void f(void*);
          void test(D* x) { f(x); }  // calls f(B*)
          


    #include B D, test() f(void*).
  • , .
  • Una estructura de código que permite una declaración preliminar (y, además, el uso de punteros como miembros de la clase) puede hacer que el código sea confuso y lento.


Veredicto



  • Intente evitar declarar previamente las entidades declaradas en otro proyecto.
  • Cuando use una función declarada en un archivo de encabezado, siempre #incluya ese archivo.
  • Cuando se usa una plantilla de clase, es preferible #incluir su archivo de encabezado.


Consulte también las reglas para la inclusión en Nombres y el Orden de inclusión .



Funciones en línea



Defina funciones como funciones en línea solo cuando sean pequeñas, por ejemplo, no más de 10 líneas.



Definición



Puede declarar funciones en línea y decirle al compilador que las incluya directamente en el código de llamada, además de la forma estándar de llamar a una función.



Pros El



uso de funciones en línea puede generar código más eficiente, especialmente cuando las funciones son pequeñas. Utilice esta función para funciones de obtención / configuración, otras funciones breves y críticas para el rendimiento.



En contra



El uso excesivo de funciones en línea puede hacer que el programa sea más lento. Además, las funciones en línea, dependiendo de su tamaño, pueden aumentar o disminuir el tamaño del código. Si se trata de funciones pequeñas, entonces el código puede minimizarse. Si la función es grande, entonces el tamaño del código puede crecer mucho. Tenga en cuenta que en los procesadores modernos, el código más sencillo se ejecuta más rápido debido a un mejor uso de la caché de instrucciones.



Veredicto



Una buena regla general es no hacer que las funciones sean insertables si exceden las 10 líneas de código. Evite hacer destructores en línea, ya que pueden contener implícitamente mucho código extra: llamadas a destructores de variables y clases base.



Otra buena regla general es que, por lo general, no tiene sentido incorporar funciones en línea que tengan bucles o instrucciones de cambio (excepto en casos degenerados en los que el bucle u otras instrucciones nunca se ejecutan).



Es importante comprender que una función en línea no necesariamente se compilará en código de esta manera. Por ejemplo, normalmente las funciones virtuales y recursivas se compilan con una llamada estándar. En general, las funciones recursivas no deben declararse funciones en línea. La razón principal para realizar funciones virtuales en línea es colocar la definición (código) en la propia definición de la clase (para documentar el comportamiento o la legibilidad), que a menudo se usa para funciones get / set.



Nombres y orden de inclusión



Inserte los archivos de encabezado en el siguiente orden: archivo emparejado (por ejemplo, foo.h - foo.cc), archivos del sistema C, biblioteca estándar C ++, otras bibliotecas, archivos de su proyecto.



Todos los encabezados del proyecto deben ser relativos al directorio de origen del proyecto sin utilizar alias de UNIX como . (directorio actual) o .. (directorio principal). Por ejemplo, google-awesome-project / src / base / logging.h debería incluirse así:



#include "base/logging.h"


Otro ejemplo: si la función principal de los archivos dir / foo.cc y dir / foo_test.cc es implementar y probar el código declarado en dir2 / foo2.h , entonces escriba los archivos de encabezado en el siguiente orden:



  1. directorio2 / foo2.h .
  2. C (: .h), <unistd.h>, <stdlib.h>.
  3. C++ ( ), <algorithm>, <cstddef>.
  4. .h .
  5. .h .


Separe cada grupo (no vacío) de archivos con una línea vacía.



Este orden de archivos le permite detectar errores cuando faltan los archivos de encabezado requeridos (sistema, etc.) en el archivo de encabezado emparejado ( dir2 / foo2.h ) y el ensamblaje de los archivos dir / foo.cc o dir / foo_test.cc correspondientes fallará. Como resultado, el error le aparecerá inmediatamente al desarrollador que trabaja con estos archivos (y no a otro equipo que solo use una biblioteca externa).



Por lo general, los archivos emparejados dir / foo.cc y dir2 / foo2.h están en el mismo directorio (por ejemplo, base / basictypes_test.cc y base / basictypes.h ), aunque esto no es necesario.



Tenga en cuenta que los archivos de encabezado C como stddef.h suelen ser intercambiables con los archivos C ++ correspondientes ( cstddef ). Se puede utilizar cualquier variación, pero es mejor seguir el estilo del código existente.



Dentro de cada sección, los archivos de encabezado se enumeran mejor en orden alfabético. Tenga en cuenta que es posible que el código escrito anteriormente no siga esta regla. Si es posible (por ejemplo, al corregir un archivo), corrija el orden de los archivos al correcto.



Se deben incluir todos los archivos de encabezado que declaran los tipos que desea, excepto donde se hayan declarado previamente . Si su código usa tipos de bar.h , no confíe en otro archivo foo.h para incluir bar.hy puede limitarse a incluir solo foo.h : include bar.h explícitamente (a menos que se indique explícitamente (quizás en la documentación) que foo.h también le dará los tipos de bar.h ).



Por ejemplo, la lista de archivos de encabezado en google-awesome-project / src / foo / internal / fooserver.cc podría verse así:



#include "foo/server/fooserver.h"
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/server/bar.h"


Excepciones



Hay casos en los que es necesario incluir archivos de encabezado según las condiciones del preprocesador (por ejemplo, según el sistema operativo utilizado). Intente mantener dicha inclusión lo más corta (localizada) posible y colóquela después de otros archivos de encabezado. Por ejemplo:



#include "foo/public/fooserver.h"
#include "base/port.h"  // For LANG_CXX11.
#ifdef LANG_CXX11
#include <initializer_list>
#endif  // LANG_CXX11


Notas:



Imagen tomada de código abierto .



All Articles