Frage

Kann ich die Reihenfolge festlegen statische Objekte zerstört werden? Gibt es eine Möglichkeit, meine gewünschte Reihenfolge zu erzwingen? Zum Beispiel in irgendeine Weise zu spezifizieren, dass ich ein bestimmtes Objekt möchte zuletzt zerstört werden, oder zumindest nach der anderen statischen Objekt?

War es hilfreich?

Lösung

Die statischen Objekte werden in umgekehrter Reihenfolge der Konstruktion zerstört. Und die Reihenfolge der Konstruktion ist sehr schwer zu kontrollieren. Das einzige, was Sie sicher sein können, ist, dass zwei Objekte in derselben Übersetzungseinheit definiert werden in der Reihenfolge der Definition aufgebaut sein. Alles andere ist mehr oder weniger zufällig.

Andere Tipps

Die anderen Antworten auf diese darauf bestehen, dass es nicht getan werden kann. Und sie haben recht, nach der Spezifikation -. Aber es ist ein Trick, dass Sie es tun lassen

Erstellen Sie nur eine Single statische Variable, einer Klasse oder Struktur, die all die anderen Dinge enthält, die sich normalerweise statische Variablen machen, etwa so:

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

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;

Sie können die Variablen in beliebiger Reihenfolge erstellen Sie müssen, und was noch wichtiger ist, vernichten sie in beliebiger Reihenfolge Sie müssen, im Konstruktor und Destruktor für StaticVariables. Um dies völlig transparent, können Sie statische Verweise auf die Variablen erstellen, etwa so:

static Var1Type &var1(*svars.var1);

Voilà - die totale Kontrolle. :-) Das heißt, ist diese zusätzliche Arbeit, und in der Regel nicht notwendig. Aber wenn es ist notwendig, es ist sehr nützlich, darüber zu wissen.

Kurze Antwort:. Im Allgemeinen wird nicht

Etwas länger beantworten: Für globale statische Objekte in einer einzigen Translation-Einheit der Initialisierungsreihenfolge oben nach unten ist, wird die Zerstörung um genau umgekehrt. Die Reihenfolge zwischen mehreren Übersetzungseinheiten ist nicht definiert.

Wenn Sie wirklich einen bestimmten Auftrag benötigen, müssen Sie dies selbst machen.

Statische Objekte in den umgekehrten Reihenfolge zerstört werden, in denen sie aufgebaut sind (zB das erste gebaute Objekt zerstört reicht), und Sie können die Reihenfolge steuern, in der statischen Objekte konstruiert werden, indem die Technik beschrieben in Artikel 47, " Stellen sie sicher, dass die globalen Objekte initialisiert werden, bevor sie gewohnt sind" in Meyers Buch Effective C ++ .

  

Zum Beispiel in irgendeine Weise zu spezifizieren, dass ich ein bestimmtes Objekt möchte zuletzt zerstört werden, oder zumindest nach der anderen statischen onject?

Stellen Sie sicher, dass es vor dem anderen statischen Objekt konstruiert wird.

  

Wie kann ich steuern, um die Konstruktion Ordnung? nicht alle der Statik in der gleichen DLL sind.

Ich werde (der Einfachheit halber) ignorieren die Tatsache, dass sie nicht in der gleichen DLL sind.

Meine paraphrasieren von Meyers' Artikel 47 (die 4 Seiten lang) ist wie folgt. Vorausgesetzt, dass Sie in einer Header-Datei wie folgt definiert global ist ...

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

... einige Code hinzufügen, um diese Datei wie diese gehören ...

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

Die Wirkung dieser wird sein, dass jede Datei, den GlobalA.h (zum Beispiel Ihrer GlobalB.cpp Quelldatei, die Ihre zweite globale Variable definiert) enthält eine statische Instanz der Inita Klasse definieren, die vor etwas gebaut werden in dieser Quelldatei sonst (zB vor Ihrer zweiten globalen Variable).

Diese Inita Klasse hat einen statischen Referenzzähler. Wenn die erste Instanz Inita aufgebaut ist, die jetzt garantiert wird, bevor Ihr GlobalB Beispiel so konstruiert ist, kann der Inita Konstruktor tun, was es um sicherzustellen, zu tun hat, dass die globalA Instanz initialisiert wird.

Theres keine Möglichkeit, es in Standard C ++ zu tun, aber wenn man eine gute Kenntnisse Ihrer spezifischen Compiler-Interna es wahrscheinlich erreicht werden kann.

In Visual C ++ die Zeiger auf die statischen init-Funktionen werden im .CRT$XI Segment (für C-Typ statische init) oder .CRT$XC Segments (für C ++ Typ statische init) Der Linker sammelt alle Erklärungen und verschmilzt sie in alphabetischer Reihenfolge. Sie können die Reihenfolge steuern, in der statische Initialisierung erfolgt durch Ihre Objekte im richtigen Segment erklärt mit

#pragma init_seg

zum Beispiel, wenn Sie Objekte der Datei A wollen, bevor Datei B erstellt werden:

Datei A.cpp:

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

Datei B.cpp:

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

.CRT$XCB wird, bevor .CRT$XCC fusioniert. Wenn die CRT iteriert durch die statischen init Funktionszeiger wird es Datei A vor B-Datei auftreten.

In Watcom das Segment XI und Variationen über #pragma initialize können bauaufsichtlich:

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

... siehe Dokumentation für mehr

Nein, kann man nicht. Sie sollten sich nicht von Bau / Zerstörung von statischen Objekten auf der anderen verlassen können.

Sie können immer ein Singleton verwenden, um die Reihenfolge der Bau / Zerstörung Ihrer globalen Ressourcen zu steuern.

Haben Sie wirklich brauchen die Variable vor main initialisiert werden?

Wenn Sie nicht über eine einfache Sprache tatsächlich nutzen können, um die Reihenfolge der Konstruktion zu kontrollieren und Zerstörung mit Leichtigkeit finden Sie hier:

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

Es ist nicht zu STOPPEN Sie tatsächlich versuchen, eine zweite Instanz der Klasse zu erstellen, aber wenn Sie die Behauptung tun wird fehlschlagen. Nach meiner Erfahrung funktioniert es gut.

Sie können effektiv eine ähnliche Funktionalität erreichen, indem ein static std::optional<T> anstelle eines T haben. initialisieren Sie es einfach, wie Sie mit einer Variablen tun würde, verwenden Sie mit indirection und zerstören sie durch std::nullopt Zuweisen (oder, für Speise-, boost::none).

Es unterscheidet sich von einem Zeiger in mit, dass es vorbelegt Speicher hat, was ich denke, was Sie wollen. Deshalb, wenn Sie es und (vielleicht viel später) zerstören neu erstellen, das Objekt wird die gleiche Adresse haben (die Sie halten können) und Sie nicht die Kosten für die dynamische Zuordnung / Aufhebung der Zuordnung zu diesem Zeitpunkt zahlen.

Verwenden boost::optional<T> wenn Sie nicht std:: / std::experimental:: haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top