Premissas
Uma das vantagens das bibliotecas somente de cabeçalho para C ++ é que elas não precisam ser compiladas separadamente.
Em C e C ++
inline
, só faz sentido se a função estiver definida em um arquivo de cabeçalho *.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
Respostas:
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.
Isso depende do sistema do compilador / vinculador, mas acho que para a maioria dos compiladores C e C ++ existentes isso é verdade.
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.
fonte
Bem, primeiro vamos demolir algumas de suas suposições:
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.
Sim, o único efeito
inline
que 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.
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 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.
fonte