2010-11-28 24 views
23

Supongamos que tengo el siguiente código (literalmente) en un archivo fuente en C++:Abolir incluir archivos en 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> es comentado de salida:

g++ -include my_cpp_std_lib_hack source.cpp 
Cuando

my_cpp_std_lib_hack es un archivo en un sitio central que incluye todos los archivos de la biblioteca de C++ estándar:

#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 interesan (como MS Visual Studio y tal vez algunos otros), y también uso encabezados precompilados.

El uso de un truco como me da las siguientes ventajas:

  • compilación rápida (porque toda la biblioteca estándar es precompilado)
  • No hay necesidad de añadir #include s cuando todo lo que quiero es añadir un poco de salida de depuración
  • No hay necesidad de recordar o mirar hacia arriba todo el tiempo dónde diablos std::max se declara
  • Una sensación de que el TEL está mágicamente integrado en el lenguaje

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

¿Se romperá este truco al escribir grandes proyectos?

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

+3

¿Qué pasa si hay dos encabezados que definen algo con el mismo nombre? – Cameron

+10

Sinceramente odio lo que has hecho, pero estoy votando tu pregunta porque realmente quiero ver respuestas sobre por qué exactamente es horrible –

+1

En realidad, en cierto modo, tiendes a terminar haciendo esto en Visual C++. Es como funcionan los encabezados precompilados. OK - stdafx.h está explícitamente incluido (a diferencia de este hack de compilación de opciones), pero sigue siendo básicamente una gran lista de todo lo que necesita en cualquier lugar, aunque la mayoría no es necesaria en la mayoría de los lugares. Como resultado, un pequeño cambio en un encabezado tiende a significar una gran reconstrucción, ya que todo tiene una dependencia de compilación en stdafx.h. Tipo de derrotas el punto, realmente. – Steve314

Respuesta

15

Lo único "incorrecto" es que se basa en un indicador de línea de comandos específico del compilador para hacer que los archivos sean compilables. Tendría que hacer algo diferente si no usa 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 depender innecesariamente de 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 de Eclipse, o lo que sea) para descubrir cómo funcionan las cosas.

Esto también puede causar problemas a los usuarios de IDE. Si el IDE no sabe qué archivos se incluyen, es posible que no pueda proporcionar la finalización automática, la exploración de fuentes, la 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. Facilita la precompilación, facilita el acceso a un puerto no entorno estándar, y también ayuda a resolver los problemas que a veces surgen cuando los encabezados se incluyen en diferentes órdenes en diferentes archivos fuente. Pero ese archivo de encabezado debe ser explícitamente incluido por cada archivo fuente; no debe haber magia.)

+2

+1 para el último paragragh –

+0

7 años después, esto es lo que he estado usando por ahora, pero parece que el clang no puede funcionar de esta manera, y * requiere * poner archivos pch en '-include' en el comando línea o Makefile. De acuerdo con [este] (http://clang.llvm.org/docs/UsersManual.html#using-a-pch-file) manual del usuario. – anatolyg

23

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

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

¿Se romperá este truco al escribir grandes proyectos?

Sí, ese es prácticamente el problema. Además, si alguien más mira el código, se estarán preguntando dónde vino el std::cout (bueno, supongamos que es un tipo definido por el usuario). Sin el #include s no van a tener idea alguna.

Sin mencionar que ahora tiene que enlazar con una tonelada de funciones de biblioteca estándar que posiblemente haya evitado enlazar (en principio podría haberse evitado).

Si desea utilizar la precompilación está bien, pero alguien debería poder compilar todos y cada uno de los archivos de implementación incluso cuando la precompilación esté desactivada.

+1

No importa que esto también rompa la búsqueda de nombres en editores como Vim. – greyfade

+1

Y no en editores como Eclipse ♪ (descubrimiento automático de configuración desde comandos de compilación = gran ganancia) ... um, solo menciono. – Kos

4

Olvídese de la aceleración de la compilación: un encabezado precompilado con plantillas no está realmente "precompilado", excepto el nombre y el análisis, por lo que he escuchado. No voy a creer en la velocidad de compilación hasta que lo vea en los puntos de referencia. :)

En cuanto a la utilidad:

Yo prefiero tener un IDE que se ocupa de mi incluye para mí (esto sigue siendo malo para C++, pero Eclipse suma ya conocido incluye con Ctrl + Shift + N con .. . bueno, fiabilidad aceptable :)).

+2

+1 - cierto, pero el "análisis" es un * lote * del trabajo en C++. –

+0

@Billy: pero no tanto como la instanciación de la plantilla. ;) – jalf

2

Hacer 'clandestine' incluye como esto también haría las pruebas más difíciles. Desea compilar el subconjunto de código más pequeño posible al probar un componente en particular. Averiguar cuál es el subconjunto es sería difícil si los encabezados/fuentes no son honestos acerca de sus dependencias, por lo que probablemente arrastre su my_cpp_std_lib_hack en cada prueba unitaria. Esto aumentaría el tiempo de compilación para sus suites de prueba un lote. Las bases de código establecidas a menudo tienen más de tres veces más código de prueba que el código regular, por lo que es probable que se convierta en un problema a medida que crezca la base de códigos.

2

Desde el GCC manual:

-include file 

archivo de proceso como si #include "archivo" apareció como la primera línea del archivo fuente primaria . Sin embargo, el primer directorio de buscado es el directorio de trabajo del preprocesador en lugar del directorio que contiene el archivo fuente principal. Si no se encuentra allí, se busca en el resto de la cadena #include "..." de búsqueda como de costumbre.

Así que lo que está haciendo es esencialmente equivalente al inicio de cada archivo con la línea

#include "my_cpp_std_lib_hack" 

que es lo que hace Visual Studio cuando se recoge archivos incluidos comúnmente en stdafx.h. Hay algunos beneficios para eso, como lo describen otros, pero su enfoque lo oculta en el proceso de compilación, de modo que nadie que mirara directamente a uno de sus archivos fuente sabría de esta magia oculta.Hacer que tu código sea opaco de esta manera no me parece un buen estilo, así que si te gustan todos los beneficios del encabezado precompilado, te sugiero que incluyas explícitamente tu archivo de hackeo.

0

Usted está haciendo algo muy malo. De hecho, está incluyendo muchos encabezados que pueden no ser necesarios. En general, esta es una muy mala idea, porque está creando dependencias innecesarias, y un cambio en cualquier encabezado requeriría la recompilación de todo. Incluso si está evitando esto mediante el uso de encabezados precompilados, todavía está vinculando a muchos objetos que puede que no necesite, lo que hace que su ejecutable sea mucho más grande de lo que debe ser.

No hay nada de malo con la forma estándar de usar los encabezados. Debes incluir todo lo que estás usando y nada más (las declaraciones directas son tus amigos). Esto hace que el código sea más fácil de seguir y le ayuda a mantener las dependencias bajo control.

0

Tratamos de no incluir el no utilizado o incluso las cosas rara vez se utiliza por ejemplo en VC++ existe

#define WIN32_LEAN_AND_MEAN //exclude rarely used stuff 

y lo que odiamos en MFC es que si quieres hacer una sencilla aplicación u se producen grandes archivo ejecutable con toda la biblioteca (si está enlazado estáticamente), así que no es una buena idea, ¿qué pasa si solo quieres usar el comando 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 argumentos ... p. Yo prefiero usar

#pragma (comment, "xxx.lib") 

de usarlo en la línea de comandos, me recuerda al menos con lo que el archivo que quiero

Eso es es mi propia opinión que el código quede estable y fácil de compilar con el fin de que se pudran como ¡El código pudriéndose es algo muy desagradable!

Cuestiones relacionadas