As bibliotecas apenas de cabeçalho são mais eficientes?

48

Premissas

  1. Uma das vantagens das bibliotecas somente de cabeçalho para C ++ é que elas não precisam ser compiladas separadamente.

  2. Em C e C ++ inline, só faz sentido se a função estiver definida em um arquivo de cabeçalho *.

  3. Tradicionalmente, em C, o layout .c / .h é usado, onde o cabeçalho representa a interface pública mínima da unidade de tradução. Da mesma forma, .cpp / hpp.

Pergunta, questão

As bibliotecas somente de cabeçalho geralmente são mais eficientes em termos de código e tempo de execução do que o layout tradicional? Em caso afirmativo, isso ocorre por causa de extensas inlining ou outras otimizações?

* - definir a função em um cabeçalho permite que o compilador veja a implementação durante a compilação de qualquer unidade de tradução e praticamente torna possível o código embutido

Vorac
fonte
2
Você ficaria surpreso em saber como muitos vinculadores C ++ modernos (GCC, MSVC, ICC etc.) podem incorporar código em várias unidades de tradução separadas. Eu diria "geralmente não" na perspectiva da eficiência, dado o número de vezes que a otimização de vinculadores desafiou minhas expectativas e conseguiu alinhar de qualquer maneira (isso exclui contextos dylib em que alinhar em um cabeçalho ou fornecer a implementação em uma biblioteca vinculada estaticamente separada pode ajudar) . No entanto, as bibliotecas apenas de cabeçalho, desde que sejam estáveis ​​na interface e na implementação, podem ser sensuais devido à facilidade com que podem ser implantadas em novos projetos.
11
Não sei se isso merece uma resposta completa, mas um grande benefício das bibliotecas apenas de cabeçalho é a facilidade de instalação e uso: Download, #include "lib.h (pp)", concluído.
WeRelic

Respostas:

44

Uma das vantagens das bibliotecas somente de cabeçalho para C ++ é que elas não precisam ser compiladas separadamente

Não, isso não é uma vantagem, muito pelo contrário - a parte principal da biblioteca deve ser compilada sempre que for incluída, não apenas uma vez. Isso normalmente aumenta o tempo de compilação. No entanto, se você estiver se referindo às vantagens listadas aqui na Wikipedia : esse artigo está falando sobre a sobrecarga administrativa reduzida referente a todo o processo de compilação, empacotamento e implantação.

Em C e C ++, o inline faz sentido apenas se a função estiver definida em um arquivo de cabeçalho *

Isso depende do sistema do compilador / vinculador, mas acho que para a maioria dos compiladores C e C ++ existentes isso é verdade.

Tradicionalmente, em C, o layout .c / .h é usado, onde o cabeçalho representa a interface pública mínima da unidade de tradução. Da mesma forma, .cpp / hpp.

Isso é mais correto. Os cabeçalhos de classe C ++ geralmente contêm mais do que a interface pública mínima - normalmente também contêm muitas coisas particulares. Para atenuar isso, coisas como o idioma PIMPL são usadas. Isso é algo como "o oposto" de uma biblioteca somente de cabeçalho, ele tenta minimizar o conteúdo necessário do cabeçalho.

Mas, para responder à sua pergunta principal: isso é uma troca. Quanto mais código de biblioteca é colocado nos arquivos de cabeçalho, mais o compilador tem a chance de otimizar o código de velocidade (se isso realmente acontecer ou se o aumento for notável, será uma questão completamente diferente). Por outro lado, muito código nos cabeçalhos aumenta o tempo de compilação. Especialmente em grandes projetos C ++, isso pode se tornar um problema sério, consulte "Design de software C ++ em larga escala", de John Lakos - embora o livro esteja um pouco desatualizado e alguns dos problemas descritos nele sejam abordados por compiladores modernos, as idéias gerais / as soluções ainda são válidas.

Em particular, quando você não está usando uma biblioteca estável (de terceiros), mas está desenvolvendo suas próprias bibliotecas durante o seu projeto, os tempos de compilação se tornam aparentes. Toda vez que você altera algo na lib, deve alterar um arquivo de cabeçalho, o que causará uma recompilação e ligação de todas as unidades dependentes.

IMHO, a popularidade das bibliotecas somente de cabeçalho é causada pela popularidade da meta-programação de modelos. Para a maioria dos compiladores, as bibliotecas modeladas devem ser apenas de cabeçalho, porque o compilador só pode iniciar o processo de compilação principal quando os parâmetros de tipo são fornecidos e, para compilação e otimização completas, o compilador deve ver "ambos de uma vez" - o código da biblioteca e o modelo valores de parâmetro. Isso torna impossível (ou pelo menos difícil) produzir unidades de compilação "pré-compiladas" para essa biblioteca.

Doc Brown
fonte
6
Portanto, em resumo, as bibliotecas somente de cabeçalho são mais convenientes e não mais eficientes ; e como o C ++ não possui nenhum gerenciador de pacotes padrão, isso ajuda a impulsionar a adoção.
Matthieu M.
6
@ MatthieuM: não, o código compilado às vezes pode ser mais eficiente e, para as bibliotecas de modelos, o design somente de cabeçalho normalmente não é uma questão de conveniência. E o aumento do tempo de compilação definitivamente não é mais conveniente.
Doc Brown
Ter o código quente nos cabeçalhos pode realmente levar a um código compilado mais eficiente, no entanto, isso não exige que todo o código esteja nos cabeçalhos e, portanto, é independente, IMHO, das bibliotecas somente de cabeçalho.
Matthieu M.
11
@ MatthieuM .: isso é certamente correto, no entanto, acho que o termo "mais conveniente" não descreve bem o caso.
Doc Brown
3
Trabalhei em um grande projeto incorporado em cima de um sistema operacional mais antigo e mais enxuto para meu empregador anterior e, nesses casos, posso atestar a dor dos longos tempos de compilação. Qualquer pessoa pega demais em arquivos de cabeçalho seria tratada sem piedade.
Fred Thomsen
15

Bem, primeiro vamos demolir algumas de suas suposições:

  1. Uma das vantagens das bibliotecas somente de cabeçalho para C ++ é que elas não precisam ser compiladas separadamente.

Compilar as coisas separadamente significa potencialmente não ter que recompilar tudo se apenas uma parte mudar.
Portanto, uma desvantagem em vez de uma vantagem.

  1. Em C e C ++, o inline faz sentido apenas se a função estiver definida em um arquivo de cabeçalho *.

Sim, o único efeito inlineque resta é a exceção à regra de definição única .
Ai de você, se essas definições são diferentes de alguma forma.

Portanto, se uma função é interna a uma unidade de compilação, marque-a static. Isso também torna o inlining mais provável, pois a função precisa estar disponível para incorporá-lo.
Ainda assim, dê uma olhada na otimização do tempo do link, conforme suportado pelo menos MSVC ++, gcc e clang.

  1. Tradicionalmente, em C, o layout .c / .h é usado, onde o cabeçalho representa a interface pública mínima da unidade de tradução. Da mesma forma, .cpp / hpp.

Bem, apenas apresentar a interface mínima é certamente um dos objetivos, obter maior estabilidade da API e ABI e minimizar o tempo de compilação.

Especialmente, as classes C ++ não são realmente voltadas para isso, pois todos os bits privados vazam para o cabeçalho, assim como os protegidos, quer você queira derivar ou não.

O padrão de design PIMPL é para reduzir esses detalhes.

A parte em que a separação da interface e da implementação falha completamente no C ++ é nos modelos.
O comitê tentou fazer algo com modelos exportados , mas isso foi abandonado por ser muito complicado e realmente não funcionar.

Agora, eles estão trabalhando em um sistema de módulos adequado , embora o processo seja lento. Isso reduz severamente o tempo de compilação e também deve aumentar a estabilidade da API e da ABI, diminuindo sua superfície.

As bibliotecas somente de cabeçalho geralmente são mais eficientes em termos de código e tempo de execução do que o layout tradicional? Em caso afirmativo, isso ocorre por causa de extensas inlining ou outras otimizações?

As bibliotecas apenas de cabeçalho podem ser mais eficientes no tamanho do código e no tempo de execução, embora isso dependa se a biblioteca é compartilhada, quanto dela é usada, de que maneira e se o inlining prova uma vitória decisiva nesse caso específico.

E o motivo pelo qual inlining é tão importante para a otimização não é porque o inlining é um grande impulso, mas devido às oportunidades de propagação constante e maior otimização que ele abre.

Desduplicador
fonte