2012-04-02 6 views
9

This answer Zitate C++ 11 Standard 3.8:Warum löschen Sie nicht ein Objekt, das einen Destruktor mit einem nicht definierten Verhalten in C++ 11 hat?

, wenn es an den destructor oder wenn ein Löschausdruck (5.3.5) nicht verwendet werden zur Freigabe der Speicherung kein expliziter Aufruf ist, wird der Destruktor nicht sein implizit aufgerufen und jedes Programm, das von den vom Destruktor erzeugten Seiteneffekten abhängt, hat ein nicht definiertes Verhalten.

Der Teil über den Destruktor, der nicht aufgerufen wird, ist klar. Angenommen, der übersprungene Destruktor hatte einen Nebeneffekt, der das Programmverhalten hätte beeinflussen sollen.

Warum ist das Programmverhalten jetzt undefiniert? Warum sollten die Nebenwirkungen nicht übersprungen werden (da der Destruktor nicht aufgerufen wird) und das Programm normal ohne Nebenwirkungen ausgeführt wird?

+2

Interessante Frage. Aber warum sollte jemand den Destruktor nicht auf einem Objekt aufrufen wollen, wenn es nicht mehr benötigt wird? – ereOn

+1

Wenn der Destruktor in diesem Fall nicht triviale Aufgaben für ex ausführt: Schließen von Ressource-Handles oder Festlegen des Status auf etwas Gültiges usw., dann wird der nicht aufgerufene Destruktor natürlich das Programm beeinflussen und zu einem nicht definierten Verhalten führen. Ich verstehe die Begründung nicht für das Überspringen von Nebenwirkungen. –

+0

@ereOn: Singletons wurden als Anwendungsfall erwähnt (dies sollte jedoch nicht als gutes Design angesehen werden). –

Antwort

5

Der wichtige Teil ist der erste Teil dieses Absatzes (Hervorhebung von mir):

Ein Programm kann die Lebensdauer eines Objekts durch Wiederverwendung des Speicher beenden, die das Objekt besetzt ...

Wenn Sie einfach den Speicher für ein Objekt wiederverwenden, dessen Destruktor nicht aufgerufen hat, dann erhalten Sie undefiniertes Verhalten. Zum Beispiel könnte das Objekt einen Thread gestartet oder einen Rückruf registriert haben oder eine andere Aktion, bei der eine externe Komponente erwarten könnte, dass das Objekt noch existiert.

+2

Ich stimme nicht zu. Das vollständige Zitat fügt * hinzu oder ruft den Destruktor explizit für ein Objekt eines Klassentyps mit einem nicht-trivialen Destruktor * auf. Also würde der Destruktor in diesem Fall aufgerufen werden. –

+0

Entschuldigung, in welchem ​​Fall? Es sagt ** oder **, also scheint mein oben stehendes Zitat sowohl für sich selbst als auch für Ihr eigenes stehen. –

+0

Aber das ist das Thema, auf das ich hinweise. Weder Zitat * steht für sich selbst *. Der Standard gibt eine Alternative, aber die Wahl ist nicht unsere. Das * für ein Objekt eines Klassentyps mit einem nicht-trivialen Destruktor * gibt das Kriterium zur Auswahl zwischen den beiden Zweigen von ** oder **. Und daher wird jedes Objekt mit einem Nicht-Trivial-Destruktor (was hier der interessante Fall ist) seinen Destruktor erhalten, der * vor * genannt wird, dessen Speicher wiederverwendet wird. –

1

Ihre Frage ergibt keinen Sinn.

Warum sollten die Nebenwirkungen nicht übersprungen werden (da der Destruktor nicht aufgerufen wird) und das Programm normal ohne Nebenwirkungen ausgeführt wird?

Sie werden übersprungen, weil sie vom Destruktor ausgelöst worden wären und nicht aufgerufen worden wären.

Meine Lektüre von: undefinierten Verhalten

und jedes Programm, das hat durch die destructor produziert an den Seiten ff ekte abhängt.

ist einfach, ich sehe es in Anbetracht von RAII. Beispiel:

#include "Object.hpp" 

struct Manager: private boost::noncopyable { 
    union Raw { 
    char _[sizeof(Object)]; 
    Object o; 
    }; 
    static Raw raw; 

    Manager() { new (raw.o) Object(); } 
    ~Manager() { raw.o.~Object(); } 
}; 

Nun, wenn ich ein Manager zuteile, vergisst, sie zu zerstören, und ordnet einen neuen, ich in einer Prise bin für mich die Speicherung der ersten erstellt Object mit einem zweiten bin überschreiben, obwohl es ist immer noch "am Leben". Dies ist ein nicht definiertes Verhalten.

1

Ich glaube, das ist in den Standard, um für Garbage Collection zu ermöglichen. Und um darauf hinzuweisen, dass sich C++ anders verhält als andere Sprachen, indem es beim Sammeln keine Destruktoren aufruft.

Es besagt ausdrücklich, dass Speicher wiederverwendet werden kann, ohne die Destruktoren der Objekte in diesem Speicherbereich aufzurufen. Wenn das Programm von auf den Destruktoren abhängt, die ausgeführt werden, wird es nicht erwartet funktionieren.

Wenn es nicht von den Destruktoren abhängen, ist alles in Ordnung.

3

In diesem Fall haben wir eine genaue Antwort. Die spezifische Zeile wurde eingeführt, um CWG 1116, "Aliasing von Gewerkschaftsmitgliedern" zu lösen.