Pergunta

Quais são os benefícios de uma biblioteca somente de cabeçalho e por que você a escreveria dessa forma, em oposição a colocar a implementação em um arquivo separado?

Foi útil?

Solução

Há situações em que uma biblioteca somente de cabeçalho é a única opção, por exemplo, ao lidar com modelos.

Ter uma biblioteca somente de cabeçalho também significa que você não precisa se preocupar com as diferentes plataformas onde a biblioteca pode ser usada.Ao separar a implementação, geralmente você faz isso para ocultar detalhes da implementação e distribuir a biblioteca como uma combinação de cabeçalhos e bibliotecas (lib, dllé ou .so arquivos).É claro que eles devem ser compilados para todos os diferentes sistemas operacionais/versões aos quais você oferece suporte.

Você também poderia distribuir os arquivos de implementação, mas isso significaria uma etapa extra para o usuário - compilar sua biblioteca antes de usá-la.

Claro, isso se aplica a um caso a caso base.Por exemplo, bibliotecas somente de cabeçalho às vezes aumentam tamanho do código e tempos de compilação.

Outras dicas

Benefícios da biblioteca somente de cabeçalho:

  • Simplifica o processo de construção.Você não precisa compilar a biblioteca e não precisa especificar a biblioteca compilada durante a etapa de link do build.Se você tiver uma biblioteca compilada, provavelmente desejará construir múltiplas versões dela:Um compilado com depuração habilitada, outro com otimização habilitada e possivelmente outro sem símbolos.E talvez ainda mais para um sistema multiplataforma.

Desvantagens de uma biblioteca somente de cabeçalho:

  • Arquivos de objetos maiores.Cada método embutido da biblioteca usado em algum arquivo de origem também obterá um símbolo fraco, definição fora de linha no arquivo de objeto compilado para esse arquivo de origem.Isso torna o compilador mais lento e também o vinculador.O compilador precisa gerar todo esse inchaço e, em seguida, o vinculador precisa filtrá-lo.

  • Compilação mais longa.Além do problema de inchaço mencionado acima, a compilação levará mais tempo porque os cabeçalhos são inerentemente maiores em uma biblioteca somente de cabeçalho do que em uma biblioteca compilada.Esses grandes cabeçalhos precisarão ser analisados ​​para cada arquivo de origem que usa a biblioteca.Outro fator é que os arquivos de cabeçalho em uma biblioteca somente de cabeçalho precisam #include cabeçalhos necessários para as definições embutidas, bem como os cabeçalhos que seriam necessários se a biblioteca tivesse sido construída como uma biblioteca compilada.

  • Compilação mais emaranhada.Você obtém muito mais dependências com uma biblioteca somente de cabeçalho por causa desses recursos extras #includeé necessário com uma biblioteca somente de cabeçalho.Altere a implementação de alguma função-chave na biblioteca e talvez seja necessário recompilar todo o projeto.Faça essa alteração no arquivo de origem de uma biblioteca compilada e tudo o que você precisa fazer é recompilar esse arquivo de origem da biblioteca, atualizar a biblioteca compilada com esse novo arquivo .o e vincular novamente o aplicativo.

  • Mais difícil para o humano ler.Mesmo com a melhor documentação, os usuários de uma biblioteca muitas vezes precisam recorrer à leitura dos cabeçalhos da biblioteca.Os cabeçalhos em uma biblioteca somente de cabeçalho são preenchidos com detalhes de implementação que atrapalham a compreensão da interface.Com uma biblioteca compilada, tudo que você vê é a interface e um breve comentário sobre o que a implementação faz, e geralmente isso é tudo que você deseja.Isso é realmente tudo que você deveria querer.Você não deveria precisar saber detalhes de implementação para saber como usar a biblioteca.

Eu sei que este é um fio antigo, mas ninguém mencionou interfaces ABI ou problemas específicos do compilador. Então eu pensei que faria.

Isso é basicamente baseado no conceito de você, ou escrevendo uma biblioteca com um cabeçalho para distribuir pessoas ou reutilizar a si mesmo vs com tudo em um cabeçalho. Se você estiver pensando em reutilizar um cabeçalho e arquivos de origem e recompilando estes em todos os projetos, isso realmente não se aplica.

Basicamente, se você compilar seu código C ++ e construir uma biblioteca com um compilador, o usuário tenta usar essa biblioteca com um compilador diferente ou uma versão diferente do mesmo compilador, então você pode obter erros de ligação ou comportamento de tempo de execução estranho devido ao binário incompatibilidade.

Por exemplo, os fornecedores do compilador muitas vezes alteram sua implementação do STL entre as versões. Se você tiver uma função em uma biblioteca que aceita um STD :: Vector, espera que os bytes nessa classe sejam organizados na maneira como foram organizados quando a biblioteca foi compilada. Se, em uma nova versão do compilador, o fornecedor fez melhorias de eficiência no STD :: Vector, o código do usuário vê a nova classe que pode ter uma estrutura diferente e passa que a nova estrutura em sua biblioteca. Tudo fica downhill de lá ... é por isso que é recomendado não passar objetos STL através dos limites da biblioteca. O mesmo se aplica a tipos C Tempo (CRT).

Enquanto fala sobre o CRT, sua biblioteca e o código-fonte do usuário geralmente precisam ser vinculados contra o mesmo CRT. Com o Visual Studio Se você construir sua biblioteca usando o CRT multithread, mas o usuário liga em relação ao Debug CRT multithread, você terá problemas de link porque sua biblioteca não pode encontrar os símbolos necessários. Não me lembro qual função foi, mas para o Visual Studio 2015 Microsoft fez uma função CRT Inline. De repente, foi no cabeçalho não a biblioteca CRT para que as bibliotecas que esperassem encontrá-lo no Link Time não poderiam mais fazer e isso gerou erros de links. O resultado foi que essas bibliotecas precisavam recompilar com o Visual Studio 2015.

Você também pode obter erros de link ou comportamento estranho se você usar a API do Windows, mas construir com diferentes configurações Unicode para o usuário da biblioteca. Isso ocorre porque a API do Windows tem funções que usam strings Unicode ou ASCII e macros / define que usam automaticamente os tipos corretos com base nas configurações Unicode do projeto. Se você passar uma corda através do limite da biblioteca, que é o tipo errado, então as coisas quebram no tempo de execução. Ou você pode achar que o programa não vincula em primeiro lugar.

Essas coisas também são verdadeiras para passar objetos / tipos através dos limites da biblioteca de outras bibliotecas de terceiros (por exemplo, um vetor de Eigen ou uma matriz GSL). Se a 3ª biblioteca do partido alterar seu cabeçalho entre você compilando sua biblioteca e seu usuário compilar seu código, as coisas vão quebrar.

Basicamente, para ser seguro, as únicas coisas que você pode passar pelos limites da biblioteca são construídas em tipos e dados antigos lisos (pod). Idealmente, qualquer pod deve estar em estruturas que são definidas em seus próprios cabeçalhos e não confiam em nenhum cabeçalho de terceiros.

Se você fornecer uma biblioteca apenas de cabeçalho, todo o código será compilado com as mesmas configurações do compilador e contra os mesmos cabeçalhos, então muitos desses problemas vão embora (fornecendo a versão do terceiro parcialmente bibliotecas que você e seus usos de usuário são compatíveis com API ). No entanto, há negativos que foram mencionados acima, como o aumento do tempo de compilação. Além disso, você pode estar executando um negócio para que você não queira entregar todos os detalhes de implementação de código-fonte para todos os seus usuários, caso um deles roube.

O principal "benefício" é que ele exige que você entregue código-fonte, então Você vai acabar com relatórios de erros sobre máquinas e com compiladores nunca ouvi falar.Quando a biblioteca é inteiramente modelos, você não tem muita escolha, mas quando você tem a escolha, o cabeçalho só é geralmente um pobre Escolha de engenharia.(Por outro lado, é claro, o cabeçalho só significa que Você não precisa documentar qualquer procedimento de integração.)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top