¿Las bibliotecas de solo encabezado son más eficientes?

48

Supuestos

  1. Una de las ventajas de las bibliotecas de solo encabezado para C ++ es que no necesitan compilarse por separado.

  2. En C y C ++ inlinetiene sentido solo si la función se define en un archivo de encabezado *.

  3. Tradicionalmente, en C, se ha utilizado el diseño .c / .h, donde el encabezado representa la interfaz pública mínima de la unidad de traducción. Del mismo modo, .cpp / hpp.

Pregunta

¿Las bibliotecas de solo encabezado son generalmente más eficientes en cuanto a código y tiempo de ejecución que el diseño tradicional? Si es así, ¿se debe a una amplia línea u otras optimizaciones?

* - la definición de la función en un encabezado permite al compilador ver la implementación durante la compilación de cualquier unidad de traducción y prácticamente hace posible la inserción de código

Vorac
fuente
2
Se sorprenderá de lo bien que muchos enlazadores C ++ modernos (GCC, MSVC, ICC, etc.) pueden incluir código en línea en unidades de traducción separadas. Yo diría "generalmente no" en la perspectiva de la eficiencia dado el número de veces que la optimización de los enlazadores desafió mis expectativas y logró alinearse de todos modos (eso excluye los contextos dylib en los que la inclusión en un encabezado o la implementación en una biblioteca separada vinculada estáticamente pueden ayudar) . Sin embargo, las bibliotecas de solo encabezado, siempre que sean estables tanto en la interfaz como en la implementación, pueden ser atractivas debido a la facilidad con que se pueden implementar en nuevos proyectos.
1
No sé si esto merece una respuesta completa, pero un gran beneficio de las bibliotecas de solo encabezado es la facilidad de instalación y uso: descarga, #include "lib.h (pp)", hecho.
WeRelic

Respuestas:

44

Una de las ventajas de las bibliotecas de solo encabezado para C ++ es que no necesitan compilarse por separado

No, eso no es una ventaja, sino todo lo contrario: la parte principal de la biblioteca debe compilarse con la frecuencia que se incluye, no solo una vez. Eso generalmente aumentará los tiempos de compilación. Sin embargo, si se refiere a las ventajas que se enumeran aquí en Wikipedia : ese artículo habla de una disminución de los gastos administrativos en relación con todo el proceso de construcción, empaquetado y despliegue.

En C y C ++ en línea solo tiene sentido si la función se define en un archivo de encabezado *

Esto depende del sistema compilador / enlazador, pero supongo que para la mayoría de los compiladores C y C ++ existentes esto es cierto.

Tradicionalmente, en C, se ha utilizado el diseño .c / .h, donde el encabezado representa la interfaz pública mínima de la unidad de traducción. Del mismo modo, .cpp / hpp.

Eso es mayormente correcto. Los encabezados de clase C ++ a menudo contienen más que la interfaz pública mínima: generalmente también contienen muchas cosas privadas. Para mitigar esto, se utilizan cosas como el idioma PIMPL . Esto es algo así como "lo contrario" de una biblioteca de solo encabezado, trata de minimizar el contenido del encabezado necesario.

Pero para responder a su pregunta principal: esto es una compensación. Cuanto más código de biblioteca se ponga en los archivos de encabezado, más posibilidades tendrá el compilador de optimizar el código para la velocidad (si esto realmente sucede, o si el incremento es notable, es una pregunta completamente diferente). Por otro lado, demasiado código en los encabezados aumenta el tiempo de compilación. Especialmente en grandes proyectos de C ++ esto puede convertirse en un problema grave, vea "Diseño de software C ++ a gran escala" de John Lakos , aunque el libro está un poco desactualizado y algunos de los problemas descritos allí son abordados por compiladores modernos, las ideas generales / Las soluciones siguen siendo válidas.

En particular, cuando no está utilizando una biblioteca estable (de terceros), pero está desarrollando sus propias bibliotecas durante su proyecto, los tiempos de compilación se hacen evidentes. Cada vez que cambie algo en la biblioteca, debe cambiar un archivo de encabezado, lo que provocará una recompilación y vinculación de todas las unidades dependientes.

En mi humilde opinión, la popularidad de las bibliotecas de solo encabezado es causada por la popularidad de la meta programación de plantillas. Para la mayoría de los compiladores, las bibliotecas con plantilla deben ser solo de encabezado porque el compilador solo puede iniciar el proceso de compilación principal cuando se proporcionan los parámetros de tipo, y para una compilación y optimización completas, el compilador debe ver "ambos a la vez": el código de la biblioteca más la plantilla valores paramétricos. Eso hace que sea imposible (o al menos difícil) producir unidades de compilación "precompiladas" para dicha biblioteca.

Doc Brown
fuente
66
En resumen, las bibliotecas de solo encabezado son más convenientes que más eficientes ; y dado que C ++ no tiene ningún administrador de paquetes estándar, esto ayuda a impulsar la adopción.
Matthieu M.
66
@MatthieuM: no, el código compilado a veces puede ser más eficiente, y para las bibliotecas de plantillas, el diseño de solo encabezado generalmente no es una cuestión de conveniencia. Y el aumento de los tiempos compilados definitivamente no es más conveniente.
Doc Brown
Tener el código activo en los encabezados podría conducir a un código compilado más eficiente, sin embargo, esto no requiere tener todo el código en los encabezados y, por lo tanto, es independiente, en mi humilde opinión, de las bibliotecas de solo encabezado.
Matthieu M.
1
@MatthieuM .: eso seguramente es correcto, sin embargo creo que el término "más conveniente" no describe bien el caso.
Doc Brown
3
Trabajé en un gran proyecto integrado además de un sistema operativo más antiguo y reducido para mi empleador anterior, y en esos casos puedo dar fe del dolor de los largos tiempos de compilación. Cualquier persona atrapada metiendo demasiado en los archivos de encabezado sería tratada sin piedad.
Fred Thomsen
15

Bueno, primero demuelemos algunos de sus supuestos:

  1. Una de las ventajas de las bibliotecas de solo encabezado para C ++ es que no necesitan compilarse por separado.

Compilar cosas por separado significa potencialmente no tener que volver a compilar todo si solo cambia una parte.
Entonces, una desventaja en lugar de una ventaja.

  1. En C y C ++ en línea solo tiene sentido si la función se define en un archivo de encabezado *.

Sí, el único efecto que inlinequeda es la excepción a la regla de una definición .
¡Ay de ustedes si esas definiciones son diferentes de alguna manera!

Entonces, si una función es interna a una unidad de compilación, márquela static. Eso también hace que la alineación sea más probable, ya que la función debe estar disponible para alinearla.
Aún así, eche un vistazo a la optimización del tiempo de enlace, como lo respaldan al menos MSVC ++, gcc y clang.

  1. Tradicionalmente, en C, se ha utilizado el diseño .c / .h, donde el encabezado representa la interfaz pública mínima de la unidad de traducción. Del mismo modo, .cpp / hpp.

Bueno, solo presentar la interfaz mínima es sin duda uno de los objetivos, lograr una mayor estabilidad API y ABI, y minimizar los tiempos de compilación.

Sin embargo, especialmente las clases de C ++ no están realmente orientadas a eso, ya que todos los bits privados se filtran en el encabezado, al igual que los protegidos, ya sea que desee derivarlos o no.

El patrón de diseño PIMPL es para reducir tales detalles.

Sin embargo, la parte donde la separación de la interfaz y la implementación falla por completo en C ++ son las plantillas.
El comité intentó hacer algo con las plantillas exportadas , pero eso ha sido abandonado como demasiado complicado y realmente no funciona.

Ahora, están trabajando en un sistema de módulos adecuado , aunque es lento. Eso reduce drásticamente los tiempos de compilación, y también debería aumentar la estabilidad API y ABI al disminuir su superficie.

¿Las bibliotecas de solo encabezado son generalmente más eficientes en cuanto a código y tiempo de ejecución que el diseño tradicional? Si es así, ¿se debe a una amplia línea u otras optimizaciones?

Las bibliotecas de solo encabezado pueden ser más eficientes en tamaño de código y tiempo de ejecución, aunque eso depende de si la biblioteca se comparte, cuánto se usa, de qué maneras y si la inclusión en línea demuestra una victoria decisiva en ese caso específico.

Y la razón por la que la alineación es tan importante para la optimización no es porque la alineación en sí misma sea un gran impulso, sino que se abre debido a las oportunidades de propagación constante y una mayor optimización.

Deduplicador
fuente