A palavra static
- chave é aquela que tem vários significados em C ++ que eu acho muito confusos e que nunca consigo entender como é que realmente deveria funcionar.
Pelo que entendi, existe a static
duração do armazenamento, o que significa que dura a vida útil do programa no caso de um global, mas quando você está falando sobre um local, significa que ele é zero inicializado por padrão.
O padrão C ++ diz isso para membros de dados da classe com a palavra static
- chave :
3.7.1 Duração estática do armazenamento [basic.stc.static]
3 A palavra-chave static pode ser usada para declarar uma variável local com duração de armazenamento estático.
4 A palavra-chave static aplicada a um membro de dados da classe em uma definição de classe fornece a duração do armazenamento estático do membro de dados.
O que isso significa com variável local ? Essa é uma variável local de função? Porque também há que quando você declara uma função local como static
sendo inicializada apenas uma vez, na primeira vez em que entra nessa função.
Ele também fala apenas sobre a duração do armazenamento em relação aos membros da classe, que tal não ser específico da instância, isso também é uma propriedade de static
no? Ou é a duração do armazenamento?
Agora, e o caso com static
o escopo do arquivo? Todas as variáveis globais são consideradas como tendo duração de armazenamento estático por padrão? O seguinte (da seção 3.7.1) parece indicar isso:
1 Todas as variáveis que não possuem duração de armazenamento dinâmico, não possuem duração de armazenamento de encadeamento e não são locais têm duração de armazenamento estático. O armazenamento para essas entidades deve durar a duração do programa (3.6.2, 3.6.3)
Como se static
relaciona com a ligação de uma variável?
Essa static
palavra-chave inteira é absolutamente confusa. Alguém pode esclarecer os diferentes usos do inglês e também me dizer quando inicializar um static
aluno?
Respostas:
Variáveis:
static
existem variáveis para o "tempo de vida" da unidade de tradução em que está definida e:constexpr
. Mais alguma coisa e você acaba com uma variável separada em cada unidade de tradução, o que é uma loucura confusa)static
, mas podem ser endereçados a partir da classe e de uma instância (comostd::string::npos
). [Nota: você pode declarar membros estáticos em uma classe, mas eles geralmente ainda devem ser definidos em uma unidade de tradução (arquivo cpp) e, como tal, existe apenas um por classe]locais como código:
Antes de qualquer função em uma unidade de conversão ser executada (possivelmente após o
main
início da execução), as variáveis com duração de armazenamento estático (escopo do namespace) nessa unidade de conversão serão "inicializadas constantemente" (paraconstexpr
onde for possível, ou zero caso contrário) e, em seguida, não- os habitantes locais são "inicializados dinamicamente" corretamente na ordem em que são definidos na unidade de tradução (para coisas comostd::string="HI";
essa não sãoconstexpr
). Por fim, as estatísticas da função local serão inicializadas na primeira vez em que a execução "atingir" a linha em que são declaradas. Todas asstatic
variáveis são destruídas na ordem inversa da inicialização.A maneira mais fácil de corrigir tudo isso é transformar todas as variáveis estáticas que não foram
constexpr
inicializadas em locais estáticos de função, o que garante que todas as suas estatísticas / globais sejam inicializadas corretamente quando você tentar usá-las, independentemente do que seja, impedindo a inicialização estática ordem fiasco .Tenha cuidado, porque quando a especificação diz que variáveis de escopo de espaço para nome têm "duração de armazenamento estático" por padrão, elas significam o bit "tempo de vida da unidade de tradução", mas isso não significa que não possa ser acessado fora do arquivo.
Funções
Significativamente mais direto,
static
geralmente é usado como uma função de membro da classe e apenas raramente é usado para uma função independente.Uma função de membro estática difere de uma função de membro regular, pois pode ser chamada sem uma instância de uma classe e, como não possui instância, não pode acessar membros não estáticos da classe. As variáveis estáticas são úteis quando você deseja ter uma função para uma classe que definitivamente não se refere absolutamente a nenhum membro da instância ou para gerenciar
static
variáveis de membro.Uma
static
função livre significa que a função não será referida por nenhuma outra unidade de conversão e, portanto, o vinculador pode ignorá-la completamente. Isso tem um pequeno número de propósitos:static void log(const char*) {}
em cada arquivo cpp, e eles podem logar de maneira diferente.fonte
classname::
escopo. As funções de membro de classe estática são como funções globais, mas com escopo definido para a classe, ou como membros normais, mas semthis
(isso não é uma escolha - essas duas devem ser equivalentes).namespace A { static int x; }
, o que significa ligação interna e é muito diferente do comportamento dos membros de dados da classe estática .A duração estática do armazenamento significa que a variável reside no mesmo local na memória durante a vida útil do programa.
A ligação é ortogonal a isso.
Eu acho que essa é a distinção mais importante que você pode fazer. Entenda isso e o resto, além de lembrá-lo, deve ser fácil (não abordando diretamente o @Tony, mas quem possa ler isso no futuro).
A palavra-chave
static
pode ser usada para indicar ligação interna e armazenamento estático, mas, em essência, são diferentes.Sim. Independentemente de quando a variável for inicializada (na primeira chamada da função e quando o caminho de execução atingir o ponto de declaração), ela residirá no mesmo local na memória durante a vida útil do programa. Nesse caso,
static
fornece armazenamento estático.Sim, todos os globais têm, por definição, duração de armazenamento estático (agora que esclarecemos o que isso significa). Mas as variáveis com escopo de namespace não são declaradas com
static
, porque isso lhes daria ligação interna, portanto, uma variável por unidade de tradução.Ele fornece ligação interna a variáveis com escopo de espaço para nome. Ele fornece aos membros e variáveis locais a duração do armazenamento estático.
Vamos expandir tudo isso:
Definitivamente, a menos que você esteja familiarizado com isso. :) Tentando evitar adicionar novas palavras-chave ao idioma, o comitê reutilizou esta, IMO, para esse efeito - confusão. É usado para significar coisas diferentes (posso dizer, provavelmente coisas opostas).
fonte
static int x
no escopo do espaço para nome, isso fornece armazenamento não estático ?Para esclarecer a questão, prefiro categorizar o uso da palavra-chave 'estática' de três formas diferentes:
(UMA). variáveis
(B) funções
(C) variáveis-membro / funções de classes
a explicação a seguir para cada um dos subtítulos:
(A) palavra-chave 'estática' para variáveis
Este pode ser um pouco complicado, no entanto, se explicado e entendido corretamente, é bem direto.
Para explicar isso, primeiro é realmente útil saber sobre o escopo, a duração e a ligação das variáveis, sem as quais as coisas sempre são difíceis de ver através do conceito obscuro da palavra-chave staic
1. Escopo : determina onde, no arquivo, a variável está acessível. Pode ser de dois tipos: (i) Local ou Escopo do Bloco . (ii) Escopo Global
2. Duração : determina quando uma variável é criada e destruída. Novamente, é de dois tipos: (i) Duração automática do armazenamento (para variáveis com escopo Local ou Bloco). (ii) Duração de armazenamento estático (para variáveis com escopo global ou variáveis locais (em uma função ou a em um bloco de código) com especificador estático ).
3. Vinculação : determina se uma variável pode ser acessada (ou vinculada) em outro arquivo. Novamente (e felizmente), ele é de dois tipos: (i) Ligação interna (para variáveis com escopo de bloco e Escopo global / Escopo de arquivo / Escopo de espaço para nome global) (ii) Ligação externa (para variáveis com apenas escopo global / Escopo de arquivo / Escopo do Namespace Global)
Vamos consultar um exemplo abaixo para entender melhor as variáveis globais e locais simples (sem variáveis locais com duração de armazenamento estático):
Agora vem o conceito de ligação. Quando uma variável global definida em um arquivo se destina a ser usada em outro arquivo, a ligação da variável desempenha um papel importante.
A ligação de variáveis globais é especificada pelas palavras-chave: (i) estática e (ii) externa
(Agora você obtém a explicação)
A palavra-chave estática pode ser aplicada a variáveis com escopo local e global e, nos dois casos, elas significam coisas diferentes. Primeiro, explicarei o uso da palavra-chave 'estática' em variáveis com escopo global (onde também esclareço o uso da palavra-chave 'extern') e, posteriormente, para aquelas com escopo local.
1. Palavra-chave estática para variáveis com escopo global
Variáveis globais têm duração estática, o que significa que não ficam fora do escopo quando um bloco de código específico (por exemplo, main ()) no qual é usado termina. Dependendo da ligação, eles podem ser acessados apenas dentro do mesmo arquivo em que são declarados (para variável global estática) ou fora do arquivo, mesmo fora do arquivo em que foram declarados (variáveis globais do tipo externo)
No caso de uma variável global com especificador externo, e se essa variável estiver sendo acessada fora do arquivo em que foi inicializada, ela deve ser declarada para frente no arquivo em que está sendo usada, assim como uma função deve ser encaminhada declarado se sua definição estiver em um arquivo diferente de onde está sendo usado.
Por outro lado, se a variável global tiver uma palavra-chave estática, ela não poderá ser usada em um arquivo fora do qual foi declarada.
(veja o exemplo abaixo para esclarecimentos)
por exemplo:
main3.cpp
agora qualquer variável em c ++ pode ser uma const ou uma não-const e, para cada 'constância', obtemos dois casos de ligação c ++ padrão, caso nenhuma seja especificada:
(i) Se uma variável global não for const, seu vínculo é externo por padrão , ou seja, a variável global não const pode ser acessada em outro arquivo .cpp por declaração direta usando a palavra-chave extern (em outras palavras, non const global variáveis têm ligação externa (com duração estática, é claro)). Também o uso da palavra-chave externa no arquivo original em que foi definida é redundante. Nesse caso, para tornar uma variável global não const inacessível ao arquivo externo, use o especificador 'estático' antes do tipo da variável .
(ii) Se uma variável global é const, seu vínculo é estático por padrão , ou seja, uma variável global const não pode ser acessada em um arquivo que não seja o local onde está definido (em outras palavras, variáveis globais const têm vínculo interno (com duração estática claro)). Também o uso da palavra-chave estática para impedir que uma variável global const seja acessada em outro arquivo é redundante. Aqui, para fazer uma variável global const ter uma ligação externa, use o especificador 'extern' antes do tipo da variável
Aqui está um resumo para variáveis de escopo global com várias ligações
A seguir, investigamos como as variáveis globais acima se comportam quando acessadas em um arquivo diferente.
2. Palavra-chave estática para variáveis com escopo local
Atualizações (agosto de 2019) na palavra-chave estática para variáveis no escopo local
Isso ainda pode ser subdividido em duas categorias:
(i) palavra-chave estática para variáveis dentro de um bloco de função e (ii) palavra-chave estática para variáveis dentro de um bloco local sem nome.
(i) palavra-chave estática para variáveis dentro de um bloco de funções.
Mencionei anteriormente que variáveis com escopo local têm duração automática, ou seja, passam a existir quando o bloco é inserido (seja um bloco normal, seja um bloco funcional) e deixam de existir quando o bloco termina, para resumir a história, variáveis com escopo local têm duração automática e variáveis de duração automática (e objetos) não têm vínculo, o que significa que não são visíveis fora do bloco de código.
Se o especificador estático for aplicado a uma variável local dentro de um bloco de função, ele altera a duração da variável de automática para estática e seu tempo de vida é toda a duração do programa, o que significa que ele possui um local de memória fixo e seu valor é inicializado apenas uma vez antes da inicialização do programa, conforme mencionado na referência cpp (a inicialização não deve ser confundida com a atribuição)
vamos dar uma olhada em um exemplo.
Observando o critério acima para variáveis locais estáticas e variáveis globais estáticas, pode-se tentar perguntar qual a diferença entre elas. Enquanto as variáveis globais estão acessíveis em qualquer ponto dentro do código (na mesma, bem como unidade de conversão diferente dependendo da const -ness e externo -ness), uma variável estático definido dentro de um bloco de função não é directamente acessível. A variável deve ser retornada pelo valor ou referência da função. Vamos demonstrar isso por um exemplo:
Mais explicações sobre a escolha da variável estática global e local estática podem ser encontradas neste encadeamento stackoverflow
(ii) palavra-chave estática para variáveis dentro de um bloco local sem nome.
variáveis estáticas dentro de um bloco local (não um bloco funcional) não podem ser acessadas fora do bloco depois que o bloco local fica fora do escopo. Sem ressalvas a esta regra.
O C ++ 11 introduziu a palavra-chave
constexpr
que garante a avaliação de uma expressão em tempo de compilação e permite que o compilador otimize o código. Agora, se o valor de uma variável const estática dentro de um escopo for conhecido em tempo de compilação, o código será otimizado de maneira semelhante à que existeconstexpr
. Aqui está um pequeno exemploEu recomendo que os leitores também procurem a diferença entre
constexpr
estatic const
para variáveis neste encadeamento de fluxo de pilha . isso conclui minha explicação para a palavra-chave estática aplicada às variáveis.B. Palavra-chave 'estática' usada para funções
em termos de funções, a palavra-chave estática tem um significado direto. Aqui, refere - se ao vínculo da função Normalmente, todas as funções declaradas em um arquivo cpp têm vínculo externo por padrão, ou seja, uma função definida em um arquivo pode ser usada em outro arquivo cpp por declaração direta.
usando uma palavra-chave estática antes da declaração da função limitar sua ligação a interna , ou seja, uma função estática não pode ser usada dentro de um arquivo fora de sua definição.
C. Staitc Palavra-chave usada para variáveis-membro e funções de classes
1. palavra-chave 'estática' para variáveis-membro de classes
Eu começo diretamente com um exemplo aqui
Neste exemplo, a variável estática m_designNum mantém seu valor e essa variável de membro particular privada (por ser estática) é compartilhada entre todas as variáveis do tipo de objeto DesignNumber
Também como outras variáveis de membro, as variáveis de membro estáticas de uma classe não estão associadas a nenhum objeto de classe, o que é demonstrado pela impressão de anyNumber na função principal
variáveis de membro estático const vs não-const na classe
(i) variáveis de membro estático da classe não const No exemplo anterior, os membros estáticos (públicos e privados) eram não constantes. O padrão ISO proíbe que os membros estáticos não-constantes sejam inicializados na classe. Portanto, como no exemplo anterior, eles devem ser inicializados após a definição da classe, com a ressalva de que a palavra-chave estática precisa ser omitida
(ii) variáveis de membro const-static da classe isso é simples e segue a convenção de outra inicialização de variável de membro const, ou seja, as variáveis de membro const static de uma classe podem ser inicializadas no ponto da declaração e no final da declaração da declaração de classe com uma ressalva de que a palavra-chave const precisa ser adicionada ao membro estático ao ser inicializada após a definição da classe.
No entanto, eu recomendaria inicializar as variáveis de membro estático const no ponto de declaração. Isso acompanha a convenção C ++ padrão e torna o código mais limpo
Para obter mais exemplos sobre variáveis estáticas de membros em uma classe, consulte o seguinte link em learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Palavra-chave 'estática' para função de membro de classes
Assim como variáveis de membro de classes podem, ser estáticas, também podem funções de membro de classes. As funções de membro normais das classes são sempre associadas a um objeto do tipo de classe. Por outro lado, funções de membro estáticas de uma classe não estão associadas a nenhum objeto da classe, ou seja, elas não possuem esse ponteiro.
Em segundo lugar, como as funções de membro estático da classe não possuem esse ponteiro, elas podem ser chamadas usando o nome da classe e o operador de resolução do escopo na função principal (ClassName :: functionName ();)
Terceiro, as funções de membro estático de uma classe só podem acessar variáveis de membro estático de uma classe, pois as variáveis de membro não estático de uma classe devem pertencer a um objeto de classe.
Para obter mais exemplos de funções membro estáticas em uma classe, consulte o seguinte link em learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/
fonte
struct Foo{static const std::string name = "cpp";};
, erro,name
devem ser definidas fora da classe; com variáveis embutidas introduzidas no c ++ 17, é possível codificar:struct Foo{static inline const std::string name = "cpp";};
2) As funções membro / membro estáticas públicas podem ser acessadas pelo nome da classe com o operador de resolução de escopo e também uma instância com o operador de ponto (por exemplo: instance.some_static_method ())Na verdade, é bastante simples. Se você declarar uma variável como estática no escopo de uma função, seu valor será preservado entre chamadas sucessivas a essa função. Assim:
será exibido em
678
vez de666
, porque lembra o valor incrementado.Quanto aos membros estáticos, eles preservam seu valor nas instâncias da classe. Portanto, o seguinte código:
imprimirá 4, porque first.a e second.a são essencialmente a mesma variável. Quanto à inicialização, veja esta pergunta.
fonte
Quando você declara uma
static
variável no escopo do arquivo, essa variável está disponível apenas nesse arquivo específico (tecnicamente, a * unidade de tradução, mas não vamos complicar muito isso). Por exemplo:a.cpp
b.cpp
main.cpp:
Para uma variável local ,
static
significa que a variável será inicializada com zero e manterá seu valor entre as chamadas:Para variáveis de classe , isso significa que há apenas uma única instância dessa variável que é compartilhada entre todos os membros dessa classe. Dependendo das permissões, a variável pode ser acessada de fora da classe usando seu nome completo.
Marcar uma função que não seja de classe como
static
torna a função acessível apenas a partir desse arquivo e inacessível a partir de outros arquivos.a.cpp
b.cpp
Para funções de membro da classe, marcá-las como
static
significa que a função não precisa ser chamada em uma instância específica de um objeto (ou seja, não possui umthis
ponteiro).fonte
Variáveis estáticas são compartilhadas entre todas as instâncias de uma classe, em vez de cada classe ter sua própria variável.
Cada instância do 'MyClass' possui seu próprio 'myVar', mas compartilha o mesmo 'myStaticVar'. Na verdade, você nem precisa de uma instância do MyClass para acessar 'myStaticVar' e pode acessá-la fora da classe, assim:
Quando usada dentro de uma função como variável local (e não como variável de membro da classe), a palavra-chave estática faz algo diferente. Permite criar uma variável persistente, sem fornecer escopo global.
É uma variável global em termos de persistência ... mas sem ser global em escopo / acessibilidade.
Você também pode ter funções de membro estáticas. Funções estáticas são basicamente funções não membros, mas dentro do espaço de nome do nome da classe e com acesso privado aos membros da classe.
Quando você chama uma função membro, há um parâmetro oculto chamado 'this', que é um ponteiro para a instância da classe que está chamando a função. As funções de membro estático não possuem esse parâmetro oculto ... elas podem ser chamadas sem uma instância de classe, mas também não podem acessar variáveis de membro não estáticas de uma classe, porque não possuem um ponteiro 'this' para trabalhar. Eles não estão sendo chamados em nenhuma instância de classe específica.
fonte
myStaticVar
precisa ser definido também. É meio importante mencionar que, ao responder uma pergunta sobre a semântica dastatic
palavra - chave, você não acha?Como não sou programador em C, não posso fornecer informações sobre o uso da estática em um programa em C, mas quando se trata de programação orientada a objetos, a estática basicamente declara uma variável, uma função ou uma classe como a mesma. durante toda a vida do programa. Considere por exemplo.
Quando você instancia esta classe no seu Main, você faz algo assim.
Essas duas instâncias de classe são completamente diferentes uma da outra e operam independentemente uma da outra. Mas se você recriar a classe A assim.
Vamos voltar para o principal novamente.
Então a1 e a2 compartilhariam a mesma cópia de int x, pelo que qualquer operação em x em a1 influenciaria diretamente as operações de x em a2. Então, se eu fosse fazer isso
Ambas as instâncias da classe A compartilham variáveis e funções estáticas. espero que isso responda sua pergunta. Meu conhecimento limitado de C me permite dizer que definir uma função ou variável como estática significa que só é visível para o arquivo que a função ou variável é definida como estática. Mas isso seria melhor respondido por um sujeito C e não por mim. O C ++ permite que as formas C e C ++ declarem suas variáveis como estáticas, pois são completamente compatíveis com C.
fonte
Sim - não global, como uma variável local de função.
Certo.
isto é, todas as instâncias de
R
compartilhamentoint R::a
-int R::a
nunca são copiadas.Efetivamente, um global que possui construtor / destruidor, quando apropriado - a inicialização não é adiada até o acesso.
Para uma função local, é externa. Acesso: É acessível para a função (a menos, é claro, você a devolve).
Para uma classe, é externa. Acesso: aplicam-se especificadores de acesso padrão (público, protegido, privado).
static
também pode especificar ligação interna, dependendo de onde é declarada (arquivo / espaço para nome).Tem muitos propósitos em C ++.
Ele é inicializado automaticamente antes
main
se estiver carregado e tiver um construtor. Pode parecer uma coisa boa, mas a ordem de inicialização está muito além do seu controle, portanto, é muito difícil manter uma inicialização complexa, e você deseja minimizar isso - se precisar de uma estática, a função local é muito melhor nas bibliotecas e projetos. Quanto aos dados com duração de armazenamento estático, tente minimizar esse design, principalmente se for mutável (variáveis globais). O 'tempo' de inicialização também varia por vários motivos - o carregador e o kernel possuem alguns truques para minimizar as pegadas de memória e adiar a inicialização, dependendo dos dados em questão.fonte
Objeto estático: podemos definir estáticos para os membros da classe usando a palavra-chave static. Quando declaramos um membro de uma classe como estático, significa que não importa quantos objetos da classe sejam criados, há apenas uma cópia do membro estático.
Um membro estático é compartilhado por todos os objetos da classe. Todos os dados estáticos são inicializados como zero quando o primeiro objeto é criado, se nenhuma outra inicialização estiver presente. Não podemos colocá-lo na definição de classe, mas ele pode ser inicializado fora da classe, como feito no exemplo a seguir, redeclarando a variável estática, usando o operador de resolução de escopo :: para identificar a qual classe pertence.
Vamos tentar o exemplo a seguir para entender o conceito de membros de dados estáticos:
Quando o código acima é compilado e executado, produz o seguinte resultado:
Membros da função estática: Ao declarar um membro da função como estático, você o torna independente de qualquer objeto específico da classe. Uma função de membro estática pode ser chamada mesmo que não exista nenhum objeto da classe e as funções estáticas sejam acessadas usando apenas o nome da classe e o operador de resolução do escopo ::.
Uma função de membro estático pode acessar apenas membros de dados estáticos, outras funções de membros estáticos e quaisquer outras funções de fora da classe.
As funções de membro estático têm um escopo de classe e não têm acesso ao ponteiro this da classe. Você pode usar uma função de membro estático para determinar se alguns objetos da classe foram criados ou não.
Vamos tentar o exemplo a seguir para entender o conceito de membros da função estática:
Quando o código acima é compilado e executado, produz o seguinte resultado:
fonte