Variáveis ​​estáticas em funções-membro

158

Alguém pode explicar como variáveis ​​estáticas em funções membro funcionam em C ++.

Dada a seguinte classe:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Se eu declarar várias instâncias de A, a chamada foo()em uma instância incrementa a variável estática iem todas as instâncias? Ou apenas aquele em que foi chamado?

Eu assumi que cada instância teria sua própria cópia i, mas percorrer algum código que parece indicar de outra forma.

monofonik
fonte

Respostas:

169

Como class Aé uma classe que não é de modelo e A::foo()é uma função que não é de modelo. Haverá apenas uma cópia static int identro do programa.

Qualquer instância do Aobjeto afetará a mesma ie a vida útil ipermanecerá durante todo o programa. Para adicionar um exemplo:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
fonte
3
Obrigado pelo bom exemplo! Haveria uma maneira de realmente alcançar algo que torna o escopo static int iespecífico da instância, de modo que, por exemplo, o1.foo(); // i = 1e $o2.foo(); // i = 1...?
Stingery
14
Embora esse possa não ser o estilo que você está procurando, tornar um membro de dados privado da classe A teria o efeito que você está descrevendo. Se você estiver preocupado com conflitos de nome, poderá adicionar um prefixo m_para indicar o status de i.
Carl
137

staticInfelizmente, a palavra-chave tem alguns significados diferentes não relacionados em C ++

  1. Quando usado para membros de dados, significa que os dados são alocados na classe e não nas instâncias.

  2. Quando usado para dados dentro de uma função, significa que os dados são alocados estaticamente, inicializados na primeira vez em que o bloco é inserido e perduram até o encerramento do programa. Além disso, a variável é visível apenas dentro da função. Esse recurso especial da estática local é frequentemente usado para implementar a construção lenta de singletons.

  3. Quando usada no nível da unidade de compilação (módulo), significa que a variável é como uma global (ou seja, alocada e inicializada antes de mainser executada e destruída após as mainsaídas), mas que a variável não estará acessível ou visível em outras unidades de compilação .

Eu adicionei alguma ênfase na parte que é mais importante para cada uso. Use (3) é um pouco desencorajado em favor de namespaces não nomeados, que também permitem declarações de classe não exportadas.

No seu código, a staticpalavra-chave é usada com o significado número 2 e não tem nada a ver com classes ou instâncias ... é uma variável da função e haverá apenas uma cópia dela.

Como corretamente iammilind disse, no entanto, poderia haver várias instâncias dessa variável se a função fosse uma função de modelo (porque nesse caso, de fato, a própria função pode estar presente em muitas cópias diferentes do programa). Mesmo nesse caso, é claro que as classes e instâncias são irrelevantes ... veja o seguinte exemplo:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}
6502
fonte
41
+ 1 para keyword static unfortunately has a few different unrelated meanings in C++:) #
287 iammilind
o mundo faz muito mais sentido depois de ler isso, OBRIGADO
Erin
Eu gosto do truque com modelos. Mal posso esperar para encontrar uma desculpa para usá-lo.
Tomáš Zato - Restabelecer Monica
Alguém recebeu uma referência por "um pouco desencorajado em favor de espaços para nome sem nome"?
austinmarton
3
@austinmarton: A frase "O uso de static para indicar 'local para unidade de tradução' está obsoleto em C ++. Use namespaces não nomeados (8.2.5.1)" está presente na Linguagem de Programação C ++ em minha edição (10ª impressão, setembro de 1999) na página 819.
6502
2

Variáveis ​​estáticas dentro de funções

  • A variável estática é criada dentro de uma função armazenada na memória estática do programa e não na pilha.

  • A inicialização da variável estática será feita na primeira chamada da função.

  • A variável estática reterá o valor em várias chamadas de função

  • A vida útil da variável estática é Program

insira a descrição da imagem aqui

Exemplos

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}
    

int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;
}

Resultado :

Variável estática

Valor variável: 0
Valor variável: 1
Valor variável: 2
Valor variável: 3
Valor variável: 4

Variável automática

Valor variável: 0
Valor variável: 0
Valor variável: 0
Valor variável: 0
Valor variável: 0

Saurabh Raoot
fonte
-2

Resposta simplificada:

As variáveis ​​estáticas, independentemente de serem membros de uma função (sem modelo) classou (sem modelo), comportam-se - tecnicamente - como um rótulo global cujo escopo é limitado à classfunção ou.

0xbadf00d
fonte
9
Não. Os Globals são inicializados na inicialização do programa, as estáticas das funções são inicializadas no primeiro uso. Esta é uma grande diferença.
6502
Eu não acho que é isso que acontece. No entanto, isso deve ser específico do compilador de qualquer maneira.
0xbadf00d
2
Então você pensa errado: 3.6.1 no padrão C ++ determina que a construção do objeto do escopo do espaço para nome com duração de armazenamento estático ocorre na inicialização; 6.7 (4) determina que em geral "... essa variável é inicializada na primeira vez que o controle passa por sua declaração; essa variável é considerada inicializada após a conclusão de sua inicialização". A propósito, essa inicialização no primeiro uso é muito útil para implementar a construção preguiçosa de singleton.
6502
3.7.4: "A inicialização constante (3.6.2) de uma entidade de escopo de bloco com duração de armazenamento estático, se aplicável, é executada antes que seu bloco seja inserido pela primeira vez. É permitida uma implementação para executar a inicialização antecipada de outras variáveis ​​de escopo de bloco com duração de armazenamento estático ou de encadeamento nas mesmas condições em que uma implementação está autorizada a inicializar estaticamente uma variável com duração de armazenamento estático ou de encadeamento no escopo do espaço para nome (3.6.2). Caso contrário, essa variável é inicializada na primeira vez em que o controle passa por sua declaração; "
precisa saber é o seguinte
1
Curiosamente, no entanto: 1) para a inicialização constante, é irrelevante discutir se uma estática local pode ser inicializada antes de entrar no bloco pela primeira vez (a variável é visível apenas dentro do bloco e a inicialização constante não produz efeitos colaterais); 2) nada no seu post é dito sobre inicialização constante; 3) estatísticas locais são muito úteis para inicialização não constante, como MyClass& instance(){ static MyClass x("config.ini"); return x; }- uma implementação portátil válida para uso de thread único exatamente porque as estatísticas locais NÃO são simplesmente como uma global, apesar do que você diz.
6502