it-swarm.com.de

Destruktor explizit aufrufen

Ich verstehe, dass wir in den meisten Fällen einen Destruktor nicht explizit aufrufen sollten. Ich habe jedoch ein Beispiel aus C++ 11 Standard N3485, Abschnitt 13.4.5, Vorlagenargumente gesehen:

Ein expliziter Destruktoraufruf für ein Objekt mit einem Typ, der eine Klassenvorlagenspezialisierung darstellt, kann die Vorlagenargumente explizit angeben. Beispiel:

template<class T> struct A {
    ~A();
}; 

void f(A<int>* p, A<int>* q) {
    p->A<int>::~A();      // OK: destructor call
    q->A<int>::~A<int>(); // OK: destructor call
}

Es scheint mir, dass wir in diesem Fall explizit Destruktor nennen können. Können Sie mir erklären, warum? Was bedeuten diese Destruktoraufrufe in diesem Beispiel? Warum sind sie vernünftig?

Eine andere Frage:

In welchen Fällen können wir Destruktoren außer bei der Implementierung von placement delete Explizit aufrufen?

Vielen Dank.

EDIT: Ich habe aus C++ FAQ herausgefunden, dass wir einen Destruktor für eine lokale Variable nicht explizit aufrufen sollten.

44
taocp

Es scheint mir, dass wir in diesem Fall explizit Destruktor nennen können. Können Sie mir erklären, warum?

Meinen Sie, warum können wir? Weil die Sprache explizite Destruktor-Aufrufe für jedes Objekt erlaubt. Wie Sie sagen, gibt es normalerweise undefiniertes Verhalten, da die meisten Objekte auf andere Weise zerstört werden, und es ist undefiniertes Verhalten, etwas zweimal zu zerstören (oder allgemeiner, um nach der Zerstörung darauf zuzugreifen). Das heißt aber nur, dass Sie es nicht tun dürfen, nicht, dass die Sprache Sie daran hindert.

Oder meinst du, warum sollten wir wollen? Denn so zerstören Sie ein Objekt, das durch Platzierung neu erstellt wurde.

Was bedeuten diese Destruktoraufrufe in diesem Beispiel?

Sie bedeuten beide dasselbe und sind äquivalent zu p->~A(); Sie nennen den Destruktor des Objekts. Das Beispiel zeigt, dass Sie hier Vorlagenargumente angeben können, wenn Sie möchten. Ich bin mir nicht sicher, warum Sie wollen würden.

Was sind die Fälle, in denen wir Destruktoren explizit außer "Placement Delete" aufrufen können?

Ich denke dass du einen Trivial Destructor (einen, der nichts tut) nennen darfst, wann immer du willst; aber es hat keinen Sinn. Ich denke, etwas zu zerstören, das mit Placement New erstellt wurde, ist der einzig legitime Grund, dies zu tun.

31
Mike Seymour

Es scheint mir, dass wir in diesem Fall explizit Destruktor nennen können. Können Sie mir erklären, warum?

Weil die Sprache es erlaubt, den Destruktor jedes Objekts aufzurufen, wann immer Sie möchten (vorausgesetzt, Sie haben Zugriff, zum Beispiel, es ist kein privater Destruktor).

Was bedeuten diese Destruktoraufrufe in diesem Beispiel?

Es ruft nur den Destruktor auf. Logischerweise bedeutet dies, dass das Objekt zerstört ist und ab diesem Zeitpunkt als Müll betrachtet werden sollte und nicht dereferenziert oder verwendet werden sollte. Technisch bedeutet dies, dass sich das Objekt in dem Zustand befindet, in dem der Destruktor es belässt. Bei einigen Objekten kann mit der Standardkonstruktion identisch sein (Sie sollten jedoch niemals jemals darauf vertrauen).

Warum sind sie vernünftig?

Manchmal müssen Sie Objekte zerstören, ohne ihren Speicher freizugeben. Dies geschieht in vielen Klassen wie variant/any, verschiedenen Skriptbindungs- und -reflexionssystemen, einigen Singleton-Implementierungen usw.

Sie können beispielsweise std::aligned_storage Verwenden, um einen Puffer für ein Objekt zuzuweisen, und anschließend mithilfe von Placement New ein Objekt in diesem Puffer erstellen. Sie können delete für dieses Objekt nicht aufrufen, da dies sowohl den Destruktor aufruft als auch versucht, den Speicher freizugeben, der ihn sichert. In diesem Fall müssen Sie den Destruktor explizit aufrufen , um das Objekt ordnungsgemäß zu zerstören.

Was sind die Fälle, in denen wir Destruktoren explizit neben Placement Delete aufrufen können?

Es gibt nicht wirklich so etwas wie "Placement Delete", außer dem entsprechenden Operator für "Placement New" (und alle Aufrufe von delete rufen implizit den Destruktor auf, mit Ausnahme derer, die der Compiler für fehlgeschlagene Konstruktionen aufruft, z. B. Ihr "Placement Delete" 'Ahnung).

Ein Beispiel, das ich oben gegeben habe. Ein weiteres Beispiel ist std::vector. Sie können Mitgliedsfunktionen wie pop_back() aufrufen. Dies muss das letzte Element im Vektor zerstören, kann jedoch nicht delete verwenden, da der Speicher, der das Objekt sichert, Teil eines größeren Puffers ist, der separat verwaltet werden muss. Das Gleiche gilt für viele andere Container, z. B. für offen adressierte Hash-Tabellen, deque und so weiter. Dies ist ein Beispiel dafür, wo Sie den template typename Verwenden möchten, um den Destruktor explizit aufzurufen.

Es ist eine Funktion, die ein Benutzer einer Bibliothek sehr selten benötigen wird, aber der Implementierer einer Bibliothek auf niedriger Ebene wie der STL oder sogar einiger Anwendungsframeworks muss hier und da verwendet werden.

25