Porque hei-de usar o código inline?

sou um desenvolvedor de C / C++, E Aqui estão algumas perguntas que sempre me desconcertaram.

    Há uma grande diferença entre o código" regular " e o código inline? Qual é a principal diferença?
  • o código inline é simplesmente uma "forma" de macros?
  • Que tipo de troca deve ser feita quando se escolhe inserir o código?
Obrigado.
Author: jonrsharpe, 2008-09-25

16 answers

    Há uma grande diferença entre o código" regular " e o código inline?
Sim e não. Não, porque uma função ou método inline tem exatamente as mesmas características que um regular, sendo o mais importante que ambos são seguros tipo. E sim, porque o código de montagem gerado pelo compilador será diferente; com uma função regular, cada chamada será traduzida em vários passos: empurrar parâmetros na pilha, fazer o salto para o função, popping os parâmetros, etc, enquanto uma chamada para uma função inline será substituída por seu código real, como uma macro.
  • o código inline é simplesmente uma "forma" de macros?

Não! Uma macro é uma simples substituição de texto, que pode levar a erros graves. Considere o seguinte código:

#define unsafe(i) ( (i) >= 0 ? (i) : -(i) )

[...]
unsafe(x++); // x is incremented twice!
unsafe(f()); // f() is called twice!
[...]

Usando uma função inline, tem a certeza de que os parâmetros serão avaliados antes de a função ser realmente realizada. Eles também serão verificados do tipo, e eventualmente convertido para corresponder aos tipos de parâmetros formais.

    Que tipo de troca deve ser feita quando se escolhe inserir o código?

Normalmente, a execução do programa deve ser mais rápida ao usar funções inline, mas com um código binário maior. Para mais informações, você deve ler GoTW # 33 .

 40
Author: Luc Touraille, 2008-09-25 12:10:46

Desempenho

Como foi sugerido em respostas anteriores, o uso da palavra-chave {[[4]} pode tornar o código mais rápido através da introdução de chamadas de funções, muitas vezes à custa de aumento de executáveis. "Inlining function calls" significa simplesmente substituir a chamada para a função alvo com o código real da função, depois de preencher os argumentos em conformidade.

No entanto, os compiladores modernos são muito bons em Interlining chamadas de funções automaticamente sem qualquer prompt da utilizador quando ajustado para uma optimização elevada. Na verdade, os compiladores são geralmente melhores em determinar o que chamadas para inline para ganho de Velocidade do que os humanos são.

Declarar funções inline explicitamente para o bem do ganho de desempenho é (quase? sempre desnecessário!

Além disso, os compiladores podem e irão ignore o pedido inline se lhes convier. Compiladores farão isso se uma chamada para a função é impossível de inline (ou seja, usando recursão não trivial ou ponteiros de função), mas também se a função é simplesmente muito grande para um ganho de desempenho significativo. Uma Regra De Definição

No entanto, declarar uma função incorporada usando a palavra-chave inline tem outros efeitos, e pode realmente ser necessário para satisfazer a regra de uma definição (ODR): esta regra na norma c++ diz que um dado símbolo pode ser declarado várias vezes, mas só pode ser definido uma vez. If the link editor (=linker) encontra várias definições de símbolos idênticos, irá gerar um erro.

Uma solução para este problema é garantir que uma unidade de compilação não exporta um dado símbolo, dando-lhe uma ligação interna, declarando-o static.

No entanto, muitas vezes é melhor marcar uma função inline em vez disso. Isto diz ao linker para juntar todas as definições desta função através de unidades de compilação em uma definição, com um endereço, e variáveis compartilhadas função-estática.

Um exemplo, considere o seguinte programa:

// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP

#include <cmath>
#include <numeric>
#include <vector>

using vec = std::vector<double>;

/*inline*/ double mean(vec const& sample) {
    return std::accumulate(begin(sample), end(sample), 0.0) / sample.size();
}

#endif // !defined(HEADER_HPP)
// test.cpp
#include "header.hpp"

#include <iostream>
#include <iomanip>

void print_mean(vec const& sample) {
    std::cout << "Sample with x̂ = " << mean(sample) << '\n';
}
// main.cpp
#include "header.hpp"

void print_mean(vec const&); // Forward declaration.

int main() {
    vec x{4, 3, 5, 4, 5, 5, 6, 3, 8, 6, 8, 3, 1, 7};
    print_mean(x);
}

Note que ambos os ficheiros .cpp incluem o ficheiro header e, portanto, a definição da função de mean. Embora o arquivo seja salvo com guardas de inclusão Dupla, isso resultará em duas definições da mesma função, embora em diferentes unidades de compilação.

Agora, se você tentar ligar essas duas unidades de compilação-por exemplo, usando o seguinte comando:

⟩⟩⟩ g++ -std=c++11 -pedantic main.cpp test.cpp
Vais ter um erro. saying "duplicate symbol _ _ Z4meanRKNSt3_ _ 16vectorIdNS _ 9allocatoridee" (which is the mangled name of our function mean).

Se, no entanto, descomentar o modificador inline em frente à definição da função, o código compila e liga correctamente.

os modelos de função são um caso especial: são Sempre alinhados, independentemente de terem sido declarados dessa forma. Isso não significa que o compilador vai ligar para eles., mas não violam a RLL. O mesmo é verdadeiro para as funções membros que são definidas dentro de uma classe ou estrutura.

 43
Author: Konrad Rudolph, 2016-06-21 10:10:50

O código Inline funciona como macros em essência, mas é um código real Real Real Real, que pode ser otimizado. As funções muito pequenas são muitas vezes boas para inlining porque o trabalho necessário para configurar a chamada de função (carregar os parâmetros nos registros apropriados) é caro em comparação com a pequena quantidade de trabalho real que o método faz. Com o inlining, não há necessidade de configurar a chamada de função, porque o código é diretamente "colado" em qualquer método que o usa.

Inlining aumenta o tamanho do Código, que é a sua principal desvantagem. Se o código é tão grande que ele não pode caber no cache do CPU, você pode obter grandes desacelerações. Você só precisa se preocupar com isso em casos raros, uma vez que não é provável que você está usando um método em tantos lugares o código aumentado causaria problemas.

Em resumo, o inlining é ideal para acelerar pequenos métodos que são chamados muitas vezes, mas não em muitos lugares (100 lugares ainda é bom , no entanto - você precisa entrar em exemplos extremos para obter qualquer significant code bloat).

Edit: como outros já salientaram, o inlining é apenas uma sugestão para o compilador. Ele pode ignorá-lo livremente se ele pensa que você está fazendo pedidos estúpidos como inlining um enorme método de 25 linhas.

 16
Author: Sander, 2008-09-25 11:51:36
    Há uma grande diferença entre o código" regular " e o código inline?

O código Sim-inline não envolve uma chamada de função, e salvar variáveis de registo para a pilha. Ele usa o espaço de programa cada vez que é 'chamado'. Então, no geral, leva menos tempo para executar porque não há ramificação no processador e economia de Estado, limpeza de caches, etc.

  • o código inline é simplesmente uma "forma" de macros?

As Macros e o código inline partilham semelhanças. a grande diferença é que o código inline é formatado especificamente como uma função para que o compilador, e futuros mantenedores, tenham mais opções. Especificamente, ele pode facilmente ser transformado em uma função se você disser ao compilador para otimizar para o espaço de código, ou um futuro mantenedor acaba expandindo-o e usando-o em muitos lugares em seu código.

  • Que tipo de troca deve ser feita quando se escolhe inserir o código?
    • Macro: uso de alto código de espaço, execução rápida, difícil para manter se a "função" for longa
    • Função
    • : Baixo uso de espaço de código, mais lento de executar, fácil de manter
    • função Inline: utilização de alto código de espaço, execução rápida, fácil de manter

deve-se notar que a gravação do registo e saltar para a função ocupa espaço de código, de modo que para funções muito pequenas uma linha Pode ocupar menos espaço do que uma função.

-Adam

 7
Author: Adam Davis, 2013-12-17 09:44:48
Depende do compilador...
Diz que tens um compilador estúpido. Ao indicar que uma função deve ser alinhada, ela irá colocar uma cópia do conteúdo da função em cada ocorrência se ela for chamada.

Vantagem: nenhuma chamada de função superior (colocar parâmetros, empurrar o PC actual, Saltar para a função, etc.). Pode ser importante na parte central de um laço grande, por exemplo.

Inconveniente: inflaciona o binário gerado.

É uma macro? Nem por isso., porque o compilador ainda verifica o tipo de parâmetros, etc. E compiladores inteligentes? Eles podem ignorar a diretiva inline, se eles "sentem" a função é muito complexa/muito grande. E talvez eles possam automaticamente inline algumas funções triviais, como simples getters/setters.
 2
Author: PhiLho, 2008-09-25 11:38:35

Inline difere das macros porque é uma dica para o compilador (compilador pode decidir não alinhar o código!) and macros are source code text generation before the compilation and as such are "forced" to be inlined.

 2
Author: Kasprzol, 2008-09-25 11:41:18

Marcar uma função em linha significa que o compilador tem a opção para incluir em "in-line" onde é chamada, se o compilador optar por fazê-lo; em contraste, uma macro irá sempre ser expandida no local. Uma função incorporada terá os símbolos de depuração adequados configurados para permitir que um depurador simbólico rastreie a origem de onde veio, enquanto que depurar macros é confuso. As funções Inline precisam ser funções válidas, enquanto macros... bem, não o faças.

Decidir declarar uma função inline é um grande espaço de compensação -- o programa será maior se o compilador decide inline (particularmente se ele também não está estático, caso em que pelo menos um não-lineares cópia é necessária para uso de todos os objetos externos); de fato, se a função for grande, isso poderia resultar em uma queda no desempenho menos como o seu código se encaixa em cache. O impulso geral de desempenho, no entanto, é apenas que você está se livrando da sobrecarga da função chamada em si; para um pequeno função chamada como parte de um laço interior, isso é um tradeoff que faz sentido.

{[[2]}Se você confiar no seu compilador, marque pequenas funções usadas em loops internos {[[[0]} liberalmente; o compilador será responsável por fazer a coisa certa ao decidir se deve ou não inline.
 1
Author: Charles Duffy, 2008-09-25 11:40:04

Se estiver a marcar o seu código como estando em linha em F. E. C++, também está a dizer ao seu compilador que o código deve ser executado em linha, ou seja. esse bloco de código será" mais ou menos " inserido onde é chamado (removendo assim o empurrão, popping e pulando na pilha). Então, sim... recomenda-se se as funções são adequadas para esse tipo de comportamento.

 0
Author: kitofr, 2008-09-25 11:37:48

" inline "é como o equivalente de 2000 a"register". Não se incomode, o compilador pode fazer um trabalho melhor de decidir o que otimizar do que você pode.

 0
Author: Paul Tomblin, 2008-09-25 11:38:31
[[2]} ao inlining, o compilador insere a implementação da função, no ponto de chamada. O que você está fazendo com isso é remover a chamada de função overhead. No entanto, não há nenhuma garantia de que todos os seus candidatos para o inlining será realmente inlined pelo compilador. No entanto, para funções menores, Compiladores sempre alinhados. Portanto, se você tem uma função que é chamada muitas vezes, mas só tem uma quantidade limitada de código - um par de linhas - você pode se beneficiar de inlining, porque o a função call overhead pode demorar mais do que a execução da função em si.

Um exemplo clássico de um bom candidato para inlining são getters para classes de concreto simples.

CPoint
{
  public:

    inline int x() const { return m_x ; }
    inline int y() const { return m_y ; }

  private:
    int m_x ;
    int m_y ;

};

Alguns compiladores (por exemplo, VC2005 ) têm uma opção para inlining agressivo, e você não precisaria de especificar a palavra-chave 'inline' ao usar essa opção.

 0
Author: QBziZ, 2008-09-25 11:43:13

Eu não vou reiterar o acima, mas vale a pena notar que as funções virtuais não serão alinhadas como a função chamada é resolvida no tempo de execução.

 0
Author: RC., 2008-09-25 11:56:40

O Inlining está normalmente activo no nível 3 de optimização (-O3 no caso do GCC). Pode ser uma melhoria significativa da velocidade em alguns casos (quando possível).

Inlining explícito em seus programas pode adicionar alguma melhoria de velocidade com o custo de um tamanho de código incisivo.

Você deve ver o que é adequado: tamanho de código ou velocidade e decidir se você deve incluí-lo em seus programas.

Podes ligar o Nível 3 da optimização e esquecer isso, deixando o o compilador faz o trabalho dele.
 0
Author: INS, 2008-09-25 11:57:56

A resposta de se você inline vem para baixo para a velocidade. Se você está em um loop apertado chamando uma função, e não é uma função super grande, mas uma em que muito do tempo é desperdiçado em chamar a função, em seguida, fazer essa função inline e você vai ter um monte de bang para o seu dinheiro.

 0
Author: stu, 2008-09-25 12:13:29

Primeiro de tudo inline é um pedido para compilador para inline a função. então é upto compiler para torná-lo inline ou não.

  1. Quando utilizar?Quando alguma vez uma função é de muito poucas linhas(para todos os acessores e mutador) mas não para recursivo funções
  2. Vantagem?O tempo necessário para invocar a chamada de função não está envolvido
  3. o compilador tem alguma função própria?Sim, quando alguma vez uma função é definida no ficheiro header dentro de uma classe
 0
Author: yesraaj, 2008-09-25 12:28:00
Inlining é uma técnica para aumentar a velocidade. Mas use um profiler para testar isso na sua situação. Eu descobri (MSVC) que o inlining nem sempre entrega e certamente não de forma espetacular. Os tempos de execução por vezes diminuíram em alguns por cento, mas em circunstâncias ligeiramente diferentes aumentaram em alguns por cento.

Se o código está a correr lentamente, saia do seu profiler para encontrar problemas e trabalhar neles.

Deixei de adicionar funções incorporadas aos ficheiros de cabeçalho, isto aumenta o acoplamento, mas dá pouco em troca.

 0
Author: , 2008-09-25 12:56:46

O código Inline é mais rápido. Não há necessidade de realizar uma chamada de função (cada chamada de função custa algum tempo). A desvantagem é que você não pode passar um ponteiro para uma função em linha ao redor, como a função realmente não existe como função e, portanto, não tem ponteiro. Também a função não pode ser exportada para o público (por exemplo, uma função em linha em uma biblioteca não está disponível dentro de binários ligando contra a biblioteca). Outra é que a seção de código em seu binário vai crescer, se você chamar o função de vários lugares (como cada vez que uma cópia da função é gerada em vez de ter apenas uma cópia e sempre pulando lá)

Normalmente não é necessário decidir manualmente se uma função deve ser inline ou não. Por exemplo, o GCC decidirá isso automaticamente dependendo do nível de otimização (-Ox) E dependendo de outros parâmetros. Ele vai levar as coisas em consideração como "Quão grande é a função?"(número de instruções), quantas vezes é chamado dentro do Código, quanto o binário vai ficar maior ao colocá-lo, e algumas outras métricas. E. g. se uma função é estático (assim não exportados de qualquer maneira) e somente uma vez dentro do seu código e você nunca use um ponteiro para a função, as chances são boas de que o GCC vai decidir inline-lo automaticamente, como ele não terá nenhum impacto negativo (o binário não ficar maiores inlining-lo apenas uma vez).

 0
Author: Mecki, 2008-09-25 13:20:39