De acordo com o que li, o compilador não é obrigado a substituir a chamada de função de uma função embutida por seu corpo, mas o fará se puder. Isso me fez pensar: por que temos a palavra em linha se for esse o caso? Por que não tornar todas as funções funções em linha por padrão e deixar o compilador descobrir se pode substituir as chamadas pelo corpo da função ou não?
c++
language-design
optimization
compilation
EpsilonVector
fonte
fonte
Respostas:
inline
é de C; não era novo no C ++.Existem palavras-chave C (
register
einline
) que foram projetadas para permitir ao programador ajudar na otimização do código. Geralmente, eles são ignorados hoje em dia, pois os compiladores podem se sair melhor na atribuição de registros e decidir quando incorporar funções (na verdade, um compilador pode incorporar ou não uma função em momentos diferentes). A geração de código nos processadores modernos é muito mais complicada do que nos mais determinísticos comuns quando Ritchie estava inventando o C.O que a palavra significa agora, em C ++, é que ela pode ter várias definições idênticas e precisa ser definida em todas as unidades de tradução que a usam. (Em outras palavras, você precisa garantir que ela possa ser incorporada.) Você pode ter uma
inline
função em um cabeçalho sem problemas, e as funções de membro definidas em uma definição de classe são automaticamente efetivasinline
.fonte
inline
.inline
foi padronizado em C ++ primeiro, embora já estivesse disponível como uma extensão de fornecedor em C .... sim, parece que foi adicionado ao padrão C em C99.inline
C99 e posteriores são diferentes das regrasinline
do C ++.Originalmente,
inline
havia uma dica muito forte de que as chamadas para a função deveriam ser incorporadas.Mas o único efeito garantido de
inline
é permitir que uma função seja definida (efetivamente de forma idêntica) em várias unidades de conversão, por exemplo, que você coloque a definição em um arquivo de cabeçalho.Atualmente, alguns compiladores estão muito interessados em seguir a dica embutida, por exemplo, g ++. E alguns compiladores levam isso menos a sério, por exemplo, Visual C ++. Mas todos têm que cumprir a garantia.
É lamentável que esses dois significados - dica de otimização e o que poderíamos chamar de definição descartável no nível do vinculador - residam com a mesma palavra-chave, porque significa que você não pode praticamente ter um sem o outro.
Também é lamentável que
inline
(ou melhor, uma palavra-chave separada sobre definição descartável) não possa ser aplicada aos dados .A necessidade de dados descartáveis no nível do vinculador aumentou à medida que os módulos somente de cabeçalho se tornaram mais populares. Por exemplo, muitas sub-bibliotecas do Boost são apenas de cabeçalho.
Para dados, você pode, no entanto, aplicar um pequeno truque com modelos. Defina-o em algum modelo de classe, forneça um
typedef
parâmetro com modelovoid
(ou o que seja). Isso ocorre porque a regra de definição única faz uma exceção específica para modelos.Notas:
¹
inline
variáveis serão suportadas no C ++ 17 .fonte
inline
.Por que não tornar todas as funções embutidas por padrão? Porque é uma troca de engenharia. Existem pelo menos dois tipos de "otimização": acelerar o programa e reduzir o tamanho (pegada de memória) do programa. Inlining geralmente acelera as coisas. Ele elimina a sobrecarga da chamada de função, evitando pressionar e extrair parâmetros da pilha. No entanto, também aumenta a área de memória do programa, porque agora toda chamada de função deve ser substituída pelo código completo da função. Para tornar as coisas ainda mais complicadas, lembre-se de que a CPU armazena pedaços de memória usados com freqüência em um cache na CPU para acesso ultra-rápido. Se você tornar a imagem de memória do programa grande o suficiente, seu programa não poderá usar o cache de maneira eficiente e, na pior das hipóteses, inlining poderá realmente tornar seu programa lento.
fonte
Para entender “inline”, você precisa entender a história e como era a vida há 20 (e 30) anos atrás.
Estávamos escrevendo código em computadores com pouca memória, portanto não era possível para um compilador processar todo o código que compunha um programa de uma só vez. O compilador também foi muito lento, portanto, você não queria recompilar o código que não havia sido alterado - levando mais de 24 horas (em um computador que custa mais que um carro de ponta) para recompilar todo o código normal em alguns projetos trabalhou em.
Portanto, cada arquivo de código foi compilado separadamente em um arquivo de objeto. Cada arquivo de objeto começou com uma lista de todas as funções que continha, juntamente com o "endereço" da função. Um arquivo de objeto também tinha uma lista de todas as funções que chamava em outros arquivos de objeto, juntamente com o local da chamada.
Um vinculador primeiro lê todos os arquivos de objetos e cria uma lista de todas as funções exportadas, juntamente com o arquivo em que estão e o endereço. Em seguida, ele releria todos os arquivos de objeto, enviando-os para o arquivo de programa, enquanto atualizava todas as chamadas de função “externas” com o endereço da função.
O vinculador não alterou ou otimizou o código de máquina produzido pelo compilador de maneira alguma, a não ser para corrigir referências a chamadas de funções externas. O vinculador fazia parte do sistema operacional e é anterior à maioria dos compiladores. Quando as pessoas escreviam um novo compilador, elas precisavam que ele trabalhasse com os vinculadores atuais e que pudessem vincular aos arquivos de objetos atuais, caso contrário, as chamadas do sistema não poderiam ser feitas.
O compilador só viu o código no arquivo “.c” ou “.cpp” que estava compilando junto com todos os arquivos de cabeçalho incluídos. Portanto, não foi possível fazer nenhuma otimização com base no código em outros arquivos ".c" ou ".cpp".
A palavra-chave “inline” permitiu que o corpo de uma função (método) fosse definido em um arquivo de cabeçalho, permitindo assim que o compilador utilizasse o código da função enquanto compilava o código que a chama. Por exemplo, digamos que você tivesse uma classe de coleção definida no arquivo .cpp, essa classe teria um método "isEmpty", que continha uma linha de código, haveria uma grande aceleração do programa resultante se, em vez de uma chamada para uma função , a chamada de função foi substituída por esta linha.
A palavra-chave “inline” era vista na época como uma maneira “barata e fácil” de permitir o encapsulamento de dados e, ao mesmo tempo, evitar o custo de chamadas de função, sem que muitos programadores tivessem acessado apenas os campos privados do objeto. (Macros onde há uma maneira muito pior de "inserir" o código que era comum na época.)
Atualmente, os “linkers” fazem muita otimização de código e tendem a ser escritos por alguma equipe como compilador. O compilador geralmente verifica se o código está correto e o "compacta", deixando a maior parte da tarefa de criação de código de máquina para o vinculador.
fonte
Vamos ver o que o padrão diz (partes importantes destacadas em negrito):
Portanto, se você quiser ter certeza, leia a documentação do seu compilador.
Incluir tudo é uma má ideia, pois pode resultar em muitos códigos de máquina duplicados ...
Então você terá que saber:
fonte
inline
reiterar o conhecimento, pois o OP parece perder uma parte, e essa é a principal razão pela qual ele não entende. Por um lado para obter um ponto ele precisa ter uma compreensão do que está abaixo desse ponto ...Deixe-me dar um bom motivo para usar a palavra-chave inline.
Em um sistema incorporado, como uma impressora de tickets ou sistema menor semelhante. O processador é muito limitado e uma chamada de função (preparando parâmetros de função na pilha, chamada, buscar parâmetros da pilha e colocar de volta a resposta etc.) pode levar vários ms para ser executada, além da própria função.
Digamos que o tempo de chamada é de cerca de 60 ms (apenas para chamadas, e não a função real) e você realiza 50 iterações (loop ou chamadas iterativas em uma árvore).
O tempo para avançar e voltar dessa chamada de função levará 60 * 50 = 3000 (3 segundos).
Se você tem memória, você definitivamente faria um inline para economizar 3 segundos.
Portanto, o inline é basicamente usado quando você precisa de velocidade de execução. Em alguns projetos com os quais me envolvi, o tempo de chamada foi maior que o tempo de execução, uma situação clássica quando usar inline.
fonte