Na reunião de padrões ISO C ++ do Oulu de 2016, uma proposta chamada Variáveis em linha foi votada no C ++ 17 pelo comitê de padrões.
Em termos leigos, quais são as variáveis embutidas, como elas funcionam e para que servem? Como as variáveis embutidas devem ser declaradas, definidas e usadas?
const
.inline
palavra - chave faz para funções. Ainline
palavra-chave, quando aplicada a funções, tem outro efeito crucial, que se traduz diretamente em variáveis. Umainline
função, presumivelmente declarada em um arquivo de cabeçalho, não resultará em erros de "símbolo duplicado" no momento do link, mesmo que o cabeçalho seja#include
d por várias unidades de conversão. Ainline
palavra-chave, quando aplicada a variáveis, terá o mesmo resultado exato. O fim.inline
é apenas uma solicitação fraca e não vinculativa ao otimizador. Os compiladores são livres para não incorporar as funções solicitadas e / ou incorporar as que você não anotou. Em vez disso, o objetivo real dainline
palavra-chave é contornar erros de definição múltipla.Respostas:
A primeira frase da proposta:
O efeito garantido de
inline
aplicado a uma função é permitir que a função seja definida de forma idêntica, com ligação externa, em várias unidades de conversão. Para a prática, isso significa definir a função em um cabeçalho, que pode ser incluído em várias unidades de conversão. A proposta estende essa possibilidade a variáveis.Portanto, em termos práticos, a proposta (agora aceita) permite que você use a
inline
palavra-chave para definir umaconst
variável de escopo de espaço para nome de ligação externa ou qualquerstatic
membro de dados de classe em um arquivo de cabeçalho, para que as várias definições resultantes quando esse cabeçalho seja incluído no várias unidades de tradução estão bem com o vinculador - apenas escolhe uma delas.Até o C ++ 14, inclusive, o mecanismo interno para isso existia, a fim de suportar
static
variáveis nos modelos de classe, mas não havia uma maneira conveniente de usar esse mecanismo. Era preciso recorrer a truques comoA partir do C ++ 17 em diante, acredito que se possa escrever apenas
... em um arquivo de cabeçalho.
A proposta inclui a redação
… O que permite que o acima seja mais simplificado para apenas
… Como observado pelo TC em um comentário a esta resposta.
Além disso, o
constexpr
especificador implicainline
em membros de dados estáticos e também em funções.Notas:
¹ Para uma função
inline
também tem um efeito de dica sobre otimização, que o compilador deve preferir substituir as chamadas dessa função pela substituição direta do código de máquina da função. Essa dica pode ser ignorada.fonte
Kath::hi
) não precisam ser const.const
restrição foi totalmente descartada.static std::string const hi = "Zzzzz...";
?As variáveis embutidas são muito semelhantes às funções embutidas. Ele sinaliza ao vinculador que apenas uma instância da variável deve existir, mesmo que a variável seja vista em várias unidades de compilação. O vinculador precisa garantir que não sejam criadas mais cópias.
Variáveis em linha podem ser usadas para definir globais em bibliotecas de cabeçalho apenas. Antes do C ++ 17, eles tinham que usar soluções alternativas (funções embutidas ou hacks de modelo).
Por exemplo, uma solução alternativa é usar o singleton de Meyer com uma função embutida:
Existem algumas desvantagens nessa abordagem, principalmente em termos de desempenho. Essa sobrecarga pode ser evitada por soluções de modelos, mas é fácil errar.
Com variáveis embutidas, você pode declará-lo diretamente (sem obter um erro do vinculador de várias definições):
Além das bibliotecas de cabeçalho apenas, existem outros casos em que variáveis em linha podem ajudar. Nir Friedman aborda esse tópico em sua palestra no CppCon: O que os desenvolvedores de C ++ devem saber sobre os globais (e o vinculador) . A parte sobre variáveis embutidas e as soluções alternativas começa aos 18m9s .
Para encurtar a história, se você precisar declarar variáveis globais que são compartilhadas entre unidades de compilação, declará-las como variáveis embutidas no arquivo de cabeçalho é simples e evita os problemas com soluções alternativas anteriores ao C ++ 17.
(Ainda existem casos de uso para o singleton do Meyer, por exemplo, se você desejar explicitamente uma inicialização lenta.)
fonte
Exemplo mínimo executável
Esse incrível recurso do C ++ 17 nos permite:
constexpr
: Como declarar constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Compile e execute:
GitHub upstream .
Consulte também: Como as variáveis embutidas funcionam?
Padrão C ++ em variáveis embutidas
O padrão C ++ garante que os endereços serão os mesmos. Rascunho padrão do C ++ 17 N4659 10.1.6 "O especificador em linha":
A cppreference https://en.cppreference.com/w/cpp/language/inline explica que, se
static
não for fornecida, ela terá ligação externa.Implementação de variável em linha do GCC
Podemos observar como é implementado com:
que contém:
e
man nm
diz sobreu
:então vemos que há uma extensão ELF dedicada para isso.
Pré-C ++ 17:
extern const
Antes de C ++ 17 e em C, podemos obter um efeito muito semelhante a um
extern const
, o que levará a um único local de memória sendo usado.As desvantagens
inline
são:constexpr
com esta técnica, apenasinline
permite que: Como declarar constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub upstream .
Apenas alternativas de cabeçalho pré-C ++ 17
Eles não são tão bons quanto a
extern
solução, mas funcionam e ocupam apenas um único local de memória:Uma
constexpr
função, porqueconstexpr
implicainline
einline
permite (força) a definição para aparecer em todas as unidades de tradução :e aposto que qualquer compilador decente atenderá a chamada.
Você também pode usar uma variável inteira estática
const
ouconstexpr
como em:mas você não pode fazer coisas como usar o endereço, ou ele se torna usado por odr, consulte também: https://en.cppreference.com/w/cpp/language/static "Membros estáticos constantes" e Definição de dados estáticos constexpr membros
C
Em C, a situação é a mesma que C ++ pré C ++ 17, enviei um exemplo em: O que significa "estático" em C?
A única diferença é que, em C ++,
const
implicastatic
em globais, mas não na semântica de C: C ++ de `const const` vs` const`Alguma maneira de incorporá-lo totalmente?
TODO: existe alguma maneira de alinhar totalmente a variável, sem usar nenhuma memória?
Muito parecido com o que o pré-processador faz.
Isso exigiria de alguma forma:
Palavras-chave:
Testado no Ubuntu 18.10, GCC 8.2.0.
fonte
inline
não tem quase nada a ver com inlining, nem para funções nem para variáveis, apesar da própria palavra.inline
não diz ao compilador para incorporar nada. Ele informa ao vinculador para garantir que haja apenas uma definição, que tem sido tradicionalmente o trabalho do programador. Então, "Alguma maneira de incorporá-lo totalmente?" é pelo menos uma questão completamente não relacionada.