Pregunta

¿Puedo controlar el orden en que se destruyen los objetos estáticos? ¿Hay alguna forma de hacer cumplir mi pedido deseado? Por ejemplo, para especificar de alguna manera que me gustaría que un determinado objeto sea destruido en último lugar, o al menos después de otro objeto estático?

¿Fue útil?

Solución

Los objetos estáticos se destruyen en el orden inverso de construcción. Y el orden de construcción es muy difícil de controlar. De lo único que puede estar seguro es de que dos objetos definidos en la misma unidad de compilación se construirán en el orden de definición. Cualquier otra cosa es más o menos aleatoria.

Otros consejos

Las otras respuestas a esto insisten en que no se puede hacer. Y tienen razón, de acuerdo con las especificaciones, pero hay un truco que te permitirá hacerlo.

Cree solo una variable estática única , de una clase o estructura que contenga todas las demás cosas que normalmente haría variables estáticas, como estas:

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

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;

Puede crear las variables en el orden que necesite y, lo que es más importante, destruirlas en el orden que necesite, en el constructor y destructor de StaticVariables. Para hacer esto completamente transparente, también puede crear referencias estáticas a las variables, así:

static Var1Type &var1(*svars.var1);

Voil & # 224; -- Control total. :-) Dicho esto, este es un trabajo extra, y generalmente innecesario. Pero cuando es necesario, es muy útil saberlo.

Respuesta corta: en general, no.

Respuesta ligeramente más larga: para objetos estáticos globales en una sola unidad de traducción, el orden de inicialización es de arriba abajo, el orden de destrucción es exactamente inverso. El orden entre varias unidades de traducción no está definido.

Si realmente necesita un pedido específico, debe hacerlo usted mismo.

Los objetos estáticos se destruyen en el reverso del orden en que se construyeron (por ejemplo, el primer objeto construido se destruye en último lugar), y puede controlar la secuencia en la que se construyen los objetos estáticos, utilizando la técnica descrita en Elemento 47, & Quot; Asegúrese de que los objetos globales se inicialicen antes de usarse & Quot; en el libro de Meyers Efectivo C ++ .

  

Por ejemplo, para especificar de alguna manera que me gustaría que un determinado objeto sea destruido en último lugar, o al menos después de otra inyección estática?

Asegúrese de que esté construido antes que el otro objeto estático.

  

¿Cómo puedo controlar la orden de construcción? no todas las estadísticas están en el mismo dll.

Ignoraré (por simplicidad) el hecho de que no están en la misma DLL.

Mi paráfrasis del artículo 47 de Meyers (que tiene 4 páginas) es la siguiente. Asumiendo que su global está definido en un archivo de encabezado como este ...

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

... agregue un código al archivo de inclusión como este ...

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

El efecto de esto será que cualquier archivo que incluya GlobalA.h (por ejemplo, su archivo fuente GlobalB.cpp que define su segunda variable global) definirá una instancia estática de la clase InitA, que se construirá antes que nada más en ese archivo fuente (por ejemplo, antes de su segunda variable global).

Esta clase InitA tiene un contador de referencia estático. Cuando se construye la primera instancia de InitA, que ahora está garantizada antes de que se construya su instancia de GlobalB, el constructor de InitA puede hacer lo que sea necesario para garantizar que la instancia de globalA se inicialice.

No hay forma de hacerlo en C ++ estándar, pero si tiene un buen conocimiento práctico de los componentes internos de su compilador específico, probablemente se pueda lograr.

En Visual C ++, los punteros a las funciones de inicio estático se encuentran en el segmento .CRT$XI (para el inicio estático de tipo C) o el segmento .CRT$XC (para el inicio estático de tipo C ++) El vinculador recopila todas las declaraciones y las combina alfabéticamente. Puede controlar el orden en que se produce la inicialización estática declarando sus objetos en el segmento adecuado usando

#pragma init_seg

por ejemplo, si desea que los objetos del archivo A se creen antes que los archivos B:

Archivo A.cpp:

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

Archivo B.cpp:

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

.CRT$XCB se fusiona antes de .CRT$XCC. Cuando el CRT itera a través de los punteros estáticos de la función init, encontrará el archivo A antes que el archivo B.

En Watcom, el segmento es XI y las variaciones en #pragma initialize pueden controlar la construcción:

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

... ver documentación para más

No, no puedes. Nunca debe confiar en el otro de construcción / destrucción de objetos estáticos.

Siempre puede usar un singleton para controlar el orden de construcción / destrucción de sus recursos globales.

¿Realmente necesita que la variable se inicialice antes de main?

Si no puede, puede usar un modismo simple para controlar realmente el orden de construcción y destrucción con facilidad, vea aquí:

#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);
}

No te DETIENE de intentar realmente crear una segunda instancia de la clase, pero si lo haces, la afirmación fallará. En mi experiencia funciona bien.

Puede lograr efectivamente una funcionalidad similar al tener un static std::optional<T> en lugar de un T. Simplemente inicialícelo como lo haría con una variable, úselo con indirección y destrúyalo asignando std::nullopt (o, para aumentar, boost::none).

Es diferente de tener un puntero porque tiene memoria preasignada, lo que supongo que es lo que quieres. Por lo tanto, si lo destruyes & Amp; (tal vez mucho más tarde) recrearlo, su objeto tendrá la misma dirección (que puede mantener) y no pagará el costo de asignación dinámica / desasignación en ese momento.

Use boost::optional<T> si no tiene std:: / std::experimental::.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top