Pergunta

Posso controlar os objetos ordem estáticos estão sendo destruídos? Existe alguma maneira de fazer cumprir a minha ordem desejada? Por exemplo, para especificar, de alguma forma que eu gostaria de um determinado objeto a ser destruído passado, ou pelo menos após o outro objeto estático?

Foi útil?

Solução

Os objetos estáticos são destruídos na ordem inversa da construção. E a ordem de construção é muito difícil de controlar. A única coisa que você pode ter certeza é que dois objetos definidos na mesma unidade de compilação será construído na ordem de definição. Qualquer outra coisa é mais ou menos aleatória.

Outras dicas

As outras respostas a esta insistem que não pode ser feito. E eles estão certos, de acordo com a especificação - mas há é um truque que lhe permitirá fazê-lo

.

Criar apenas um única variável estática, de uma classe ou struct que contém todas as outras coisas que você faria normalmente variáveis ??estáticas, assim:

class StaticVariables {
    public:
    StaticVariables(): pvar1(new Var1Type), pvar2(new Var2Type) { };
    ~StaticVariables();

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;

Você pode criar as variáveis ??em qualquer ordem que você precisa, e mais importante, destruir -los em qualquer ordem você precisa, no construtor e destruidor para StaticVariables. Para fazer esta completamente transparente, você pode criar referências estáticas para as variáveis ??também, assim:

static Var1Type &var1(*svars.var1);

Voilà - controle total. :-) Dito isto, este é um trabalho extra, e geralmente desnecessário. Mas quando se é necessário, é muito útil para saber sobre ele.

Resposta curta:. Em geral, não

resposta ligeiramente mais: Por objetos estáticos globais em uma única tradução-unidade a ordem de inicialização é de cima para baixo, a ordem de destruição é exatamente inversa. A ordem entre várias-unidades de tradução é indefinido.

Se você realmente precisa de uma ordem específica, você precisa fazer isso sozinho.

objectos estáticos são destruídos no reverso da ordem na qual eles são construídos (por exemplo, o primeiro objecto construído é destruído último), e que possa controlar a sequência na qual os objectos estáticos são construídas, utilizando a técnica descrita no item 47, " Certifique-se de que os objetos globais são inicializados antes de serem utilizados " no livro Meyers' Effective C ++ .

Por exemplo, para especificar, de alguma forma que eu gostaria de um determinado objeto a ser destruído passado, ou pelo menos após o outro onject estática?

Certifique-se de que ele é construído antes do outro objeto estático.

Como posso controlar a ordem de construção? nem todos os estática estão na mesma dll.

Eu vou ignorar (para simplificar) o fato de que eles não estão na mesma DLL.

Meu paráfrase do item Meyers' 47 (que é de 4 páginas) é a seguinte. Supondo que você global está definido em um arquivo de cabeçalho como este ...

//GlobalA.h
extern GlobalA globalA; //declare a global

... adicionar algum código para que incluem arquivo como este ...

//GlobalA.h
extern GlobalA globalA; //declare a global
class InitA
{
  static int refCount;
public:
  InitA();
  ~InitA();
};
static InitA initA;

O efeito disso será que qualquer arquivo que inclui GlobalA.h (por exemplo, o arquivo de origem GlobalB.cpp que define a sua segunda variável global) vai definir uma instância estática da classe INITA, que será construído antes de qualquer coisa mais nesse arquivo de origem (por exemplo, antes de sua segunda variável global).

classe Este INITA tem um contador de referência estático. Quando a primeira instância INITA é construído, que agora está garantido para ser antes de sua instância GlobalB é construído, o construtor INITA pode fazer o que tem que fazer para garantir que a instância globalA é inicializado.

Não há nenhuma maneira de fazê-lo em C ++ padrão, mas se você tem um bom conhecimento de seus internos do compilador específicas trabalhando isto provavelmente pode ser alcançado.

No Visual C ++ os ponteiros para as funções de inicialização estáticos estão localizados no segmento .CRT$XI (para o tipo C de inicialização estática) ou segmento .CRT$XC (para C ++ inicialização estática tipo) O vinculador recolhe todas as declarações e mescla-los em ordem alfabética. Você pode controlar a ordem em que inicialização estática ocorre por declarar seus objetos no segmento apropriado usando

#pragma init_seg

Por exemplo, se você quiser objetos arquivo de à ser criado antes de arquivos do B:

a.cpp arquivo:

#pragma init_seg(".CRT$XCB")
class A{}A;

B.cpp arquivo:

#pragma init_seg(".CRT$XCC")
class B{}B;

.CRT$XCB se fundiram em antes .CRT$XCC. Quando os itera CRT através dos ponteiros função init estáticos ele irá encontrar ficheiro A antes de arquivo B.

Watcom o segmento é XI e variações sobre #pragma Inicializar pode controlar construção:

#pragma initialize before library
#pragma initialize after library
#pragma initialize before user

... consulte a documentação para mais

Não, você não pode. Você nunca deve contar com o outro de construção / destruição de objetos estáticos.

Você sempre pode usar um singleton para controlar a ordem de construção / destruição de seus recursos globais.

Você realmente precisa a variável a ser inicializado antes main?

Se você não pode usar uma simples linguagem para realmente controlar a ordem de construção e destruição com facilidade, consulte aqui:

#include <cassert>

class single {
    static single* instance;

public:
    static single& get_instance() {
        assert(instance != 0);
        return *instance;
    }

    single()
    // :  normal constructor here
    {
        assert(instance == 0);
        instance = this;
    }

    ~single() {
        // normal destructor here
        instance = 0;
    }
};
single* single::instance = 0;

int real_main(int argc, char** argv) {
    //real program here...

    //everywhere you need
    single::get_instance();
    return 0;
}

int main(int argc, char** argv) {
    single a;
    // other classes made with the same pattern
    // since they are auto variables the order of construction
    // and destruction is well defined.
    return real_main(argc, argv);
}

Ele não o impede de realmente tentar criar uma segunda instância da classe, mas se você fizer a afirmação irá falhar. Na minha experiência, ele funciona bem.

Você pode efetivamente obter uma funcionalidade semelhante por ter um static std::optional<T> em vez de um T. Apenas inicializar-lo como você faria com uma variável, uso com engano e destruí-lo, atribuindo std::nullopt (ou, por impulso, boost::none).

É diferente de ter um ponteiro na medida em que tem memória pré-alocado, o que é que eu acho que você quer. Portanto, se você destruí-lo e (talvez muito mais tarde) recriá-lo, o seu objeto terá o mesmo endereço (que você pode manter) e você não paga o custo de alocação dinâmica / deallocation naquele momento.

Use boost::optional<T> se você não tem std:: / std::experimental::.

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