Pergunta

Se uma variável é declarada como static no âmbito de uma função é apenas inicializado uma vez e mantém o seu valor entre chamadas de função. O que exatamente é a sua vida? Quando seu construtor e destruidor são chamados?

void foo() 
{ 
    static string plonk = "When will I die?";
}
Foi útil?

Solução

O tempo de vida de variáveis ??função static começa pela primeira vez [0] o fluxo de programa encontrar a declaração e termina no término do programa. Isso significa que o tempo de execução deve executar algumas contabilidade, a fim de destruir-lo somente se ele realmente foi construído.

Além disso, uma vez que a norma diz que os destruidores de objetos estáticos deve executar na ordem inversa da conclusão da sua construção [1] , ea ordem de construção pode depender do programa específico de execução , a ordem de construção devem ser levadas em conta.

Exemplo

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Output:

C:> sample.exe
Criado em foo
Destruída em foo

C:> sample.exe 1 | Criado em se
Criado em foo
Destruída em foo
Destruída em se

C:> sample.exe 1 2 | Criado em foo
Criado em se
Destruída em se
Destruída em foo

[0] Desde C ++ 98 [2] tem nenhuma referência a vários segmentos como este será comportam-se em um ambiente multi-threaded não é especificado, e pode ser problemático como Roddy menciona.

[1] C ++ 98 secção 3.6.3.1 [basic.start.term]

[2] Em C ++ 11 estática são inicializados de forma thread-safe, este também é conhecido como mágica Estática .

Outras dicas

Motti está certo sobre a ordem, mas há algumas outras coisas a considerar:

Os compiladores normalmente usam uma variável de sinalizador oculto para indicar se a estática locais já foram inicializados, e esta bandeira é verificado em cada entrada para a função. Obviamente este é um pequeno impacto na performance, mas o que é mais uma preocupação é que este sinalizador não é garantido para ser thread-safe.

Se você tem um local estático como acima, e foo é chamado de vários segmentos, você pode ter condições de corrida causando plonk ser inicializado incorretamente ou até mesmo várias vezes. Também, neste caso plonk pode ficar destruído por um fio diferente do que aquele que a construiu.

Apesar do que o padrão diz, eu ficaria muito cuidado com a ordem real de destruição estática local, porque é possível que você pode sem querer contar com uma estática sendo ainda válido depois de ter sido destruída, e isso é realmente difícil de rastrear baixa.

As explicações existentes não são realmente completa sem a regra real do padrão, encontrado em 6.7:

A-inicialização de zero de todas as variáveis ??do bloco de escopo com duração de armazenagem estática ou duração de armazenamento thread é executada antes de qualquer outra inicialização ocorre. inicialização constante de uma entidade bloco escopo com duração de armazenamento estático, se for o caso, é realizada antes do seu bloco é inserido em primeiro lugar. Uma implementação é permitida para efectuar a inicialização precoce de outras variáveis ??bloco-escopo com duração de armazenamento estático ou fio sob as mesmas condições que uma aplicação está autorizada a estaticamente inicializar uma variável com duração de armazenamento estático ou de fios no âmbito espaço de nomes. Caso contrário, uma tal variável é inicializada pela primeira vez, o controlo passa, através da sua declaração; tal variável é considerado um inicializado após a conclusão da sua inicialização. Se a inicialização sai lançando uma exceção, a inicialização não está completa, por isso vai ser julgado novamente na próxima controle de tempo entra na declaração. Se o controle entra na declaração simultaneamente enquanto a variável está sendo inicializado, a execução concorrente deverá aguardar a conclusão da inicialização. Se o controle re-entra na declaração recursiva enquanto a variável está sendo inicializado, o comportamento é indefinido.

FWIW, Codegear C ++ Builder não destruir na ordem esperada de acordo com o padrão.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... que é outra razão para não confiar na ordem destruição!

O Variáveis ??estáticas são entram em jogo uma vez que o inicia a execução do programa e permanecerá disponível até as extremidades execução do programa.

As variáveis ??estáticas são criadas no segmento de dados da memória .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top