Pergunta

Se definirmos uma função de membro dentro da própria definição de classe, ela é necessariamente tratada em linha ou é apenas uma solicitação ao compilador que ele pode ignorar.

Foi útil?

Solução

Sim, funções definidas dentro de um corpo de classe são implicitamente inline.

(Como em outras funções declaradas inline Isso não significa que o complier deve realizar expansão embutida em locais onde a função é chamada, apenas permite os relaxamentos permitidos da "regra de uma definição", combinados com o requisito de que uma definição deve ser incluída em todas as unidades de tradução em que a função é usada.)

Outras dicas

Conforme declarado por outros, um método definido em uma classe é solicitado automaticamente em linha. É útil entender o porquê.

Suponha que não fosse. Você teria que gerar código para essa função e, em todos os lugares, é chamado, um salto para a instrução da sub -rotina teria que fazer referência ao local, através do vinculador.

class A {
public:
  void f() { ... your code ... }
};

Toda vez que esse código é visto, se não estiver embutido, o compilador só pode assumir que ele deve ser gerado, para gerar um símbolo. Suponha que fosse assim:

A__f_v:

Se esse símbolo fosse global, se você incluísse esse código de classe várias vezes em módulos diferentes, você terá um erro de símbolo multiplicado definido no horário do link. Portanto, não pode ser global. Em vez disso, é o arquivo local.

Imagine que você inclua o arquivo de cabeçalho acima em vários módulos. Em cada um, ele gerará uma cópia local desse código. O que é melhor do que não compilar, mas você está recebendo várias cópias do código quando realmente precisa de apenas uma.

Isso lidera a seguinte conclusão: se o seu compilador não for inline uma função, você estará significativamente melhor declarando -o em algum lugar uma vez e não solicitando que ela seja inlinada.

Infelizmente, o que é e não está embutido não é portátil. É definido pelo escritor do compilador. Uma boa regra é sempre fazer com que cada revestimento, principalmente todas as funções que elas mesmas chamam de função, embutida, enquanto você remove a sobrecarga. Qualquer coisa abaixo de três linhas de código linear está quase certamente ok. Mas se você tiver um loop no código, a questão é se o compilador permitirá que ele seja embutido e, mais ao ponto, quanto benefício você veria, mesmo que fizesse o que quiser.

Considere este código embutido:

inline int add(int a, int b) { return a + b; }

Não é apenas tão pequeno quanto o protótipo estaria no código -fonte, mas o idioma da montagem gerado pelo código embutido é menor que a chamada para uma rotina seria. Portanto, esse código é menor e mais rápido.

E, se você estiver passando em constantes:

int c= add(5,4);

Está resolvido no momento da compilação e não há código.

No GCC, notei recentemente que, mesmo que eu não seja o código embutido, se for local para um arquivo, eles irão furtivamente o embelezar de qualquer maneira. Somente se eu declarar a função em um módulo de origem separado que eles não otimizarão a chamada.

No outro extremo do espectro, suponha que você solicite inline em uma peça de código de 1000 linhas. Mesmo que o seu compilador seja bobo o suficiente para acompanhá -lo, a única coisa que você salva é a chamada em si, e o custo é que toda vez que você chama, o compilador deve colar todo esse código. Se você chamar esse código n vezes , seu código cresce pelo tamanho da rotina * n. Portanto, qualquer coisa maior que 10 linhas não vale a pena, exceto o caso especial em que é chamado apenas um número muito pequeno de vezes. Um exemplo disso pode estar em um método privado chamado por apenas 2 outros.

Se você solicitar para embrulhar um método que contém um loop, ele só faz sentido se geralmente executar um pequeno número de vezes. Mas considere um loop que itera um milhão de vezes. Mesmo que o código esteja inlinado, a porcentagem de tempo gasta na chamada é pequena. Portanto, se você tem métodos com loops, que tendem a ser maiores de qualquer maneira, vale a pena remover do arquivo de cabeçalho porque eles a) tendem a ser rejeitados como alinhados pelo compilador e B) mesmo que estejam inlinados, são geralmente não vai fornecer nenhum benefício

É necessariamente tratado pelo compilador como uma solicitação de inline - que pode ignorar. Existem alguns idiomas para definir algumas funções no cabeçalho (por exemplo, destruidores virtuais vazios) e algumas definições de cabeçalho necessárias (funções de modelo), mas fora isso, veja Gotw #33 Para maiores informações.

Alguns observaram que o compilador pode até mesmo em linha de funções que você nunca pediu, mas não tenho certeza se isso derrotaria o objetivo de solicitar uma função.

É realmente inlinado - mas qualquer solicitação em linha pode ser ignorada pelo compilador.

É uma solicitação ao compilador que ele pode ignorar.

O padrão ISO C ++ de 2003 diz

7.1.2/2 Uma declaração de função (8.3.5, 9.3, 11.4) com um especificador embutido declara uma função em linha. O especificador embutido indica à implementação que a substituição embutida do corpo da função no ponto de chamada deve ser preferida à chamada de função usual
mecanismo. Uma implementação não é necessária para executar isso em linha
substituição no ponto de chamada; No entanto, mesmo que este embutido
A substituição é omitida, as outras regras para funções em linha definidas por 7.1.2 ainda serão respeitadas.

7.1.2/3 Uma função definida dentro de uma definição de classe é um inline
função. O especificador embutido não deve aparecer em uma declaração de função de escopo de bloco.

7.1.2/4 Uma função embutida deve ser definida em todas as unidades de tradução em
que é usado e terá exatamente a mesma definição em cada
Caso (3.2). [Nota: uma chamada para a função embutida pode ser encontrada
Antes de sua definição aparecer na unidade de tradução. ] Se uma função com a ligação externa for declarada em linha em uma unidade de tradução, ela será declarada em linha em todas as unidades de tradução em que aparece; Nenhum diagnóstico é necessário. Uma função em linha com a ligação externa deve ter o mesmo endereço em todas as unidades de tradução. Uma variável local estática em um externo embutido
função sempre se refere ao mesmo objeto. Uma corda literal em um
Função em linha externa é o mesmo objeto em tradução diferente
unidades.

Há duas coisas que não devem ser agrupadas:

  1. Como você marca uma função como está embutida: defina -a com embutido na frente da assinatura ou defina -a no ponto de declaração;
  2. O que o compilador tratará como marcação em linha: independentemente de como você marcou a função como embutida, ela será tratada como uma solicitação pelo compilador.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top