Abolir los archivos de inclusión en C++


Supongamos que tengo el siguiente código (literalmente) en un archivo fuente de C++:

// #include <iostream> // superfluous, commented-out
using std::cout;
using std::endl;

int main()
{
    cout << "Hello World" << endl;
    return 0;
}

Puedo compilar este código aunque #include <iostream> esté comentado:

g++ -include my_cpp_std_lib_hack source.cpp

Donde my_cpp_std_lib_hack es un archivo en una ubicación central que incluye todos los archivos de la Biblioteca Estándar de C++:

#include <ciso646>
#include <climits>
#include <clocale>
...
#include <valarray>
#include <vector>

Por supuesto, puedo usar opciones de compilación adecuadas para todos los compiladores que me importan (que son MS Visual Studio y tal vez algunos otros), y también uso encabezados precompilados.

Utilizando tal truco me da las siguientes ventajas:

  • Compilación rápida (porque toda la Biblioteca Estándar está precompilada)
  • No es necesario agregar #include s cuando todo lo que quiero es agregar alguna salida de depuración
  • No hay necesidad de recordar o buscar todo el tiempo dónde diablos std::max se declara
  • Una sensación de que el STL está mágicamente integrado en el lenguaje

Así que me pregunto: ¿estoy haciendo algo muy mal aquí?

¿Este hack se descompondrá al escribir los grandes proyectos?

Tal vez todos los demás ya usan esto, y nadie me lo dijo?

Author: anatolyg, 2010-11-28

7 answers

Lo único "incorrecto" es que usted está confiando en un indicador de línea de comandos específico del compilador para hacer que los archivos sean compilables. Tendrías que hacer algo diferente si no usas GCC. La mayoría de los compiladores probablemente proporcionan una característica equivalente, pero es mejor escribir código fuente portátil en lugar de confiar innecesariamente en las características de su entorno de compilación específico.

Otros programadores no deberían tener que descifrar sus Makefiles (o archivos Ant, o espacios de trabajo Eclipse, o lo que sea) para averigua cómo funcionan las cosas.

Esto también puede causar problemas para los usuarios de IDE. Si el IDE no sabe qué archivos se incluyen, es posible que no pueda proporcionar finalización automática, navegación de fuentes, refactorización y otras características similares.

(FWIW, creo que es una buena idea tener un archivo de encabezado que incluya todos los encabezados de biblioteca estándar que está utilizando en su proyecto. Hace que la precompilación sea más fácil, hace que sea más fácil portar a un no estándar entorno, y también ayuda a hacer frente a los problemas que a veces surgen cuando los encabezados se incluyen en diferentes órdenes en diferentes archivos de origen. Pero ese archivo de cabecera debe ser explícitamente incluido por cada archivo fuente; no debe haber magia.)

 15
Author: Kristopher Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-30 22:45:43

Así que me pregunto: ¿estoy haciendo algo muy mal aquí?

Sí. Claro, tus encabezados están precompilados, pero el compilador todavía tiene que hacer cosas como búsquedas de nombres en toda la masa de cosas incluida que ralentiza la compilación.

¿Este hack se descompondrá al escribir grandes proyectos?

Sí, ese es más o menos el problema. Además, si alguien más mira ese código, se preguntará dónde std::cout (bueno, supongamos que es un usuario definido tipo) vino de. Sin los #includes no van a tener idea alguna.

Por no mencionar, ahora usted tiene que enlazar contra un montón de características de la biblioteca estándar que usted puede tener (probablemente podría haber) evitar enlazar contra en primer lugar.

Si quieres usar precompilación está bien, pero alguien debería ser capaz de compilar todos y cada uno de los archivos de implementación incluso cuando la precompilación está desactivada.

 23
Author: Billy ONeal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-28 20:43:20

Olvídese de la velocidad de compilación-un encabezado precompilado con plantillas no es realmente "precompilado" excepto por el nombre y el análisis, por lo que he oído. No creeré en la velocidad de compilación hasta que la vea en los benchmarks. :)

En cuanto a la utilidad:

Prefiero tener un IDE que maneje mis includes por mí (esto sigue siendo malo para C++, pero Eclipse ya agrega inclusiones conocidas con ctrl+shift+n con... bueno, fiabilidad aceptable:)).

 4
Author: Kos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-28 20:55:42

Hacer 'clandestino' incluye como este también haría pruebas más difíciles. Desea compilar un subconjunto de código más pequeño posible al probar un componente en particular. Averiguar qué es ese subconjunto sería difícil si los encabezados/fuentes no están siendo honestos acerca de sus dependencias, por lo que probablemente solo arrastraría su my_cpp_std_lib_hack en cada prueba de unidad. Esto aumentaría el tiempo de compilación para sus conjuntos de pruebas a lot. Las bases de código establecidas a menudo tienen más más de tres veces más código de prueba que el código normal, por lo que es probable que esto se convierta en un problema a medida que su base de código crezca.

 2
Author: evadeflow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-28 22:14:20

Del manual del CCG :

-include file

Procesar el archivo como si #include "file" apareciera como la primera línea del archivo fuente principal. Sin embargo, el el primer directorio buscado por el archivo es directorio de trabajo del preprocesador en lugar del directorio que contiene el archivo fuente principal. Si no se encuentra allí, se busca en el remainder of the #include "(en inglés)..." búsqueda encadenar como siempre.

Así que lo que estás haciendo es esencialmente equivalente a comenzar cada archivo con la línea

#include "my_cpp_std_lib_hack"

Que es lo que Visual Studio hace cuando recopila archivos comúnmente incluidos en stdafx.h. Hay algunos beneficios de que, como se indica por otros, pero su enfoque oculta esto incluir en el proceso de compilación, por lo que nadie que miró directamente a uno de sus archivos de origen sabría de esta magia oculta. Hacer que su código sea opaco de esta manera no me parece un buen estilo, así que si está interesado en todos los beneficios de encabezado precompilado, le sugiero explícitamente incluye tu archivo de hackeo.

 2
Author: beldaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-28 23:01:56

Estás haciendo algo muy mal. Usted está incluyendo con éxito un montón de encabezados que podrían no ser necesarios. En general, esta es una muy mala idea, porque está creando dependencias innecesarias, y un cambio en cualquier encabezado requeriría recompilación de todo. Incluso si está evitando esto mediante el uso de encabezados precompilados, todavía está enlazando a muchos objetos que puede que no necesite, lo que hace que su ejecutable sea mucho más grande de lo que necesita ser.

Realmente no hay nada malo con la forma estándar de usar encabezados. Debe incluir todo lo que está utilizando, y no más (las declaraciones de reenvío son sus amigos). Esto hace que el código sea más fácil de seguir y le ayuda a mantener las dependencias bajo control.

 0
Author: Dima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-29 01:40:25

Tratamos de no incluir lo que no se usa o incluso lo que rara vez se usa, por ejemplo, en VC++ hay

#define WIN32_LEAN_AND_MEAN //exclude rarely used stuff

Y lo que odiamos en MFC es que si u quiere hacer una aplicación simple u producirá un gran archivo ejecutable con toda la biblioteca (si está enlazado estáticamente), por lo que no es una buena idea ¿qué pasa si u solo quiere usar el cout mientras que el otro no??

Otra cosa que no me gusta pasar argumentos a través de la línea de comandos porque puedo dejar el proyecto por un tiempo, y olvidar cuáles son los argumento... por ejemplo, prefiero usar

#pragma (comment, "xxx.lib")

Que usarlo en la línea de comandos, me recuerda al menos con qué archivo quiero

Esa es mi propia opinión hacer que su código estable y fácil de compilar con el fin de pudrirse como la descomposición del código es una cosa muy desagradable !!!!!

 0
Author: Dr. Mina Mounir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-29 02:47:43