¿Qué orden debe incluir los archivos que se deben especificar, es decir, cuáles son las razones para incluir un encabezado antes que otro?
Por ejemplo, ¿los archivos del sistema, STL y Boost van antes o después de los archivos de inclusión locales?
¿Qué orden debe incluir los archivos que se deben especificar, es decir, cuáles son las razones para incluir un encabezado antes que otro?
Por ejemplo, ¿los archivos del sistema, STL y Boost van antes o después de los archivos de inclusión locales?
Respuestas:
¡No creo que haya un pedido recomendado, siempre que se compile! Lo que es molesto es cuando algunos encabezados requieren que se incluyan otros encabezados primero ... Eso es un problema con los encabezados en sí, no con el orden de las inclusiones.
Mi preferencia personal es ir de local a global, cada subsección en orden alfabético, es decir:
Mi razonamiento para 1. es que debería probar que cada encabezado (para el cual hay un cpp) se puede #include
d sin requisitos previos (terminus technicus: el encabezado es "autónomo"). Y el resto parece fluir lógicamente desde allí.
Lo más importante a tener en cuenta es que sus encabezados no deberían depender de que se incluyan primero otros encabezados. Una forma de asegurar esto es incluir sus encabezados antes que cualquier otro encabezado.
"Pensar en C ++" en particular menciona esto, haciendo referencia al "Diseño de software C ++ a gran escala" de Lakos:
Los errores de uso latente pueden evitarse asegurando que el archivo .h de un componente se analice por sí mismo, sin declaraciones o definiciones proporcionadas externamente ... Incluir el archivo .h como la primera línea del archivo .c asegura que ninguna pieza crítica falta información intrínseca a la interfaz física del componente en el archivo .h (o, si la hay, la descubrirá tan pronto como intente compilar el archivo .c).
Es decir, incluir en el siguiente orden:
Si alguno de los encabezados tiene un problema para ser incluido en este orden, corríjalo (si es suyo) o no lo use. Boicotee las bibliotecas que no escriben encabezados limpios.
La guía de estilo C ++ de Google argumenta casi lo contrario, sin ninguna justificación en absoluto; Yo personalmente tiendo a favorecer el enfoque de Lakos.
Sigo dos reglas simples que evitan la gran mayoría de los problemas:
También sigo las pautas de:
En otras palabras:
#include <stdio.h>
#include <string.h>
#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"
Aunque, siendo pautas, eso es algo subjetivo. Las reglas, por otro lado, las hago cumplir rígidamente, incluso hasta el punto de proporcionar archivos de encabezado 'wrapper' con incluir guardias e incluir agrupados si algún desarrollador desagradable de terceros no se suscribe a mi visión :-)
Para agregar mi propio ladrillo a la pared.
Por lo general, voy así:
// myproject/src/example.cpp
#include "myproject/example.h"
#include <algorithm>
#include <set>
#include <vector>
#include <3rdparty/foo.h>
#include <3rdparty/bar.h>
#include "myproject/another.h"
#include "myproject/specific/bla.h"
#include "detail/impl.h"
Cada grupo separado por una línea en blanco del siguiente:
También tenga en cuenta que, además de los encabezados del sistema, cada archivo está en una carpeta con el nombre de su espacio de nombres, simplemente porque es más fácil rastrearlos de esta manera.
#define
los que estropean otro código) y para evitar dependencias implícitas. Por ejemplo, si nuestro archivo de encabezado de base de código foo.h
realmente depende de, <map>
pero en todas partes se usó en .cc
archivos, <map>
ya estaba incluido, probablemente no lo notaremos. Hasta que alguien trató de incluir foo.h
sin incluir primero <map>
. Y luego se molestarían.
.h
tiene al menos uno .cpp
que lo incluye primero (de hecho, en mi código personal, la prueba de Unidad asociada lo incluye primero, y el código fuente lo incluye en su grupo legítimo ) Con respecto a no ser influenciado, si alguno de los encabezados incluye, <map>
entonces todos los encabezados incluidos después están influenciados de todos modos, por lo que me parece una batalla perdida.
Header corresponding to this cpp file first (sanity check)
. ¿Hay algo en particular si #include "myproject/example.h"
se mueve al final de todo incluye?
Yo recomiendo:
Y, por supuesto, el orden alfabético dentro de cada sección, cuando sea posible.
Utilice siempre declaraciones de reenvío para evitar correos electrónicos innecesarios #include
en sus archivos de encabezado.
Estoy bastante seguro de que esta no es una práctica recomendada en ningún lugar del mundo cuerdo, pero me gusta alinear el sistema por longitud de nombre de archivo, ordenado léxicamente dentro de la misma longitud. Al igual que:
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
Creo que es una buena idea incluir sus propios encabezados antes que otras personas, para evitar la vergüenza de la dependencia del orden de inclusión.
windows.h
.
Esto no es subjetivo. Asegúrese de que sus encabezados no dependan de estar #include
en un orden específico. Puede estar seguro de que no importa en qué orden incluya encabezados STL o Boost.
Primero incluya el encabezado correspondiente al .cpp ... en otras palabras, source1.cpp
debe incluir source1.h
antes de incluir cualquier otra cosa. La única excepción que se me ocurre es cuando utilizo MSVC con encabezados precompilados, en cuyo caso, está obligado a incluir stdafx.h
antes que nada.
Razonamiento: incluir los source1.h
archivos anteriores a cualquier otro garantiza que pueda estar solo sin sus dependencias. Si source1.h
toma una dependencia en una fecha posterior, el compilador lo alertará de inmediato para agregar las declaraciones de reenvío requeridas asource1.h
. Esto a su vez garantiza que los dependientes puedan incluir encabezados en cualquier orden.
Ejemplo:
source1.h
class Class1 {
Class2 c2; // a dependency which has not been forward declared
};
source1.cpp
#include "source1.h" // now compiler will alert you saying that Class2 is undefined
// so you can forward declare Class2 within source1.h
...
Usuarios de MSVC: recomiendo utilizar encabezados precompilados. Por lo tanto, mueva todas las #include
directivas para encabezados estándar (y otros encabezados que nunca cambiarán) a stdafx.h
.
Incluya del más específico al menos específico, comenzando con el correspondiente .hpp para el .cpp, si existe. De esa manera, se revelarán las dependencias ocultas en los archivos de encabezado que no sean autosuficientes.
Esto se complica por el uso de encabezados precompilados. Una forma de evitar esto es, sin hacer que su compilador sea específico del proyecto, es usar uno de los encabezados del proyecto como el archivo de cabecera precompilado.
Es una pregunta difícil en el mundo C / C ++, con tantos elementos más allá del estándar.
Creo que el orden del archivo de encabezado no es un problema grave siempre que se compile, como dijo squelart.
Mi idea es: si no hay conflicto de símbolos en todos esos encabezados, cualquier orden está bien, y el problema de dependencia del encabezado se puede solucionar más adelante agregando #include líneas al .h defectuoso.
La verdadera molestia surge cuando algún encabezado cambia su acción (marcando las condiciones #if) de acuerdo con los encabezados anteriores.
Por ejemplo, en stddef.h en VS2005, hay:
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Ahora el problema: si tengo un encabezado personalizado ("custom.h") que debe usarse con muchos compiladores, incluidos algunos más antiguos que no se proporcionan offsetof
en los encabezados de sus sistemas, debería escribir en mi encabezado:
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
Y asegúrese de decirle al usuario que #include "custom.h"
después de todos los encabezados del sistema, de lo contrario, la línea de offsetof
stddef.h confirmará un error de redefinición de macro.
Oramos para no encontrarnos con más de tales casos en nuestra carrera.