Wird ein 'leerer' Konstruktor oder Destruktor dasselbe tun wie das generierte?
Nehmen wir an, wir haben eine (Spielzeug -) C++ - Klasse wie die folgenden:
class Foo {
public:
Foo();
private:
int t;
};
Da kein Destruktor definiert ist, einen C++ - compiler erstellen sollte, man automatisch für die Klasse Foo. Wenn der Destruktor nicht benötigen, zu bereinigen keine dynamisch zugewiesenen Speicher (das ist, könnten wir vernünftigerweise Vertrauen auf den Destruktor der compiler gibt uns), wird die Definition eines leeren Destruktor, dh.
Foo::~Foo() { }
tun die gleiche Sache wie der compiler-generierte? Was über einen leeren Konstruktor --Foo::Foo() { }
?
Wenn es Unterschiede, wo gibt es Sie? Wenn nicht, ist eine Methode der anderen vorgezogen?
InformationsquelleAutor der Frage Andrew Song | 2009-06-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wird es nicht die gleiche Sache (nichts, im wesentlichen). Aber es ist nicht das gleiche, wie wenn Sie nicht es zu schreiben. Da schreiben Sie den Destruktor benötigen eine funktionierende Basis-Klasse Destruktor. Wenn die Basisklasse destructor privat ist oder wenn es einen anderen Grund kann es nicht aufgerufen werden, dann ist dein Programm fehlerhaft ist. Betrachten Sie dieses
Dass ist OK, solange Ihr nicht verlangen, zu zerstören, ein Objekt des Typs B (und damit implizit der Typ A) - wie wenn Sie nie rufen Sie löschen auf einem dynamisch erzeugten Objekt, oder Sie erstellen Sie niemals ein Objekt, der es in den ersten Platz. Wenn Sie das tun, dann wird der compiler zeigt eine entsprechende Diagnose. Nun, wenn Sie sorgen, dass man sich ausdrücklich
Dass man versuchen wird implizit rufen Sie den Destruktor der Basis-Klasse, und zu bewirken, dass eine Diagnose bereits bei der Bestimmung der Zeit der
~B
.Es ist ein weiterer Unterschied, der dreht sich um die definition des destruktors und implizite Aufrufe Mitglied Destruktoren. Betrachten Sie dieses smart pointer Mitglied
Nehmen wir an, das Objekt vom Typ
C
erstellt wird, in der definition von Einem Konstruktor in der.cpp
- Datei, die enthält auch die definition von structC
. Nun, wenn Sie mit structA
erfordern und Zerstörung einerA
Objekt, der compiler wird eine implizite definition der Destruktor, so wie in dem Fall oben. Dass der Destruktor wird implizit auch rufen Sie den Destruktor der auto_ptr-Objekt. Und, löschen den Zeiger, er hält sich, dass Punkte, dieC
Objekt - ohne zu wissen, die definition vonC
! Erschienen in der.cpp
- Datei, in dem struct Einen Konstruktor definiert ist.Dies ist tatsächlich ein häufiges problem in der Implementierung des pimpl-idiom. Die Lösung hier ist das hinzufügen von ein Destruktor und einer leeren definition in der
.cpp
- Datei, wobei die StrukturC
definiert ist. Zu der Zeit, es ruft den Destruktor seiner Mitglieder, er wird dann wissen, die definition von structC
und können richtig nennen, der Destruktor.Beachten Sie, dass
boost::shared_ptr
nicht haben, dass problem: Es stattdessen Bedarf es eines ganzheitlichen geben, wenn der Konstruktor aufgerufen wird, in gewisser Weise.Einem anderen Punkt, wo es macht einen Unterschied in der aktuelle C++ ist, wenn Sie verwenden möchten
memset
und Freunde auf so ein Objekt, einen Benutzer deklarierten Destruktor. Solche Typen sind keine Hülsen mehr (plain old data), und diese sind nicht zulässig bit-kopiert. Beachten Sie, dass diese Einschränkung ist nicht wirklich notwendig - und das nächste C++ - version hat sich verbessert, die situation auf diesem, so dass es erlaubt Ihnen, die noch wenig-kopieren Sie solche Typen, solange andere, wichtigere änderungen werden nicht vorgenommen.Seit Ihr gefragt für Konstruktoren: Gut, für diese viel die gleichen Dinge, die wahr sind. Beachten Sie, dass Konstruktoren enthalten ebenfalls implizite Aufrufe von Destruktoren. Auf Dinge wie auto_ptr, diese Anrufe (auch wenn Sie nicht tatsächlich erfolgt zur Laufzeit - die Reine Möglichkeit schon geht es hier) machen den gleichen Schaden wie für Destruktoren, und passiert, wenn etwas in den Konstruktor wirft - der compiler ist dann erforderlich, rufen Sie den Destruktor der Mitglieder. Diese Antwort macht die Verwendung von impliziten definition von default-Konstruktoren.
Auch, das gleiche gilt für die Sichtbarkeit und PODness, dass ich sagte, über den Destruktor oben.
Gibt es einen wichtigen Unterschied bezüglich der Initialisierung. Wenn Sie einen Benutzer deklarierten Konstruktor Ihre Art nicht erhalten Wert Initialisierung der member mehr, und es ist bis zu Ihrem Konstruktor zu tun, keine Initialisierung nötig. Beispiel:
In diesem Fall die folgende ist immer wahr
Während der folgenden ist Undefiniertes Verhalten, weil
b
wurde nie initialisiert (der Konstruktor weggelassen). Der Wert kann null sein, kann aber auch andere komisch Wert. Versucht zu Lesen, von so einer nicht initialisierten Objekt führt zu undefiniertem Verhalten.Dies gilt auch für die Verwendung dieser syntax bei
new
wienew A()
(beachten Sie die Klammern am Ende - werden Sie weggelassen Wert die Initialisierung nicht durchgeführt wird, und da gibt es keinen user-deklarierten Konstruktor, könnte es initialisieren,a
verlassen wird, nicht initialisiert).InformationsquelleAutor der Antwort Johannes Schaub - litb
Ich weiß, ich bin zu spät in die Diskussion, dennoch meine Erfahrung sagt, dass der compiler verhält sich anders, wenn er vor einem leeren Destruktor im Vergleich zu einem compiler erzeugt. Zumindest dies ist der Fall mit MSVC++ 8.0 (2005) und MSVC++ 9.0 (2008).
Beim Blick auf die generierte assembly für einige code-making-Verwendung von expression templates, merkte ich, dass im release-Modus, den Anruf zu meinem
BinaryVectorExpression operator + (const Vector& lhs, const Vector& rhs)
war nie eingebettet. (bitte nicht achten Sie auf die genauen Typen-und Bediener-Signatur).Weitere diagnose des Problems, ich konnte die verschiedenen Compiler-Warnungen Sind Standardmäßig Deaktiviert. Die C4714 Warnung ist besonders interessant. Es wird abgegeben, indem der compiler, wenn eine Funktion markiert mit
__forceinline
nicht inlined dennoch.Ich konnte die C4714 Warnung und ich kenn die Betreiber mit
__forceinline
und ich überprüfen konnte, meldet der compiler Sie nicht in der Lage war zu inline den Anruf an den Betreiber.Unter den Gründen, die in der Dokumentation beschrieben, der compiler fehlschlägt, um die inline-Funktion markiert mit
__forceinline
für:Dies ist der Fall, meine
BinaryVectorExpression operator + (const Vector& lhs, const Vector& rhs)
.BinaryVectorExpression
zurückgegebenen Wert und auch wenn der Destruktor leer ist, macht es diesen Rückgabewert als unwindable Objekt. Hinzufügenthrow ()
zu den Destruktor nicht helfen, die compiler und Ich vermeiden, mit Ausnahme Spezifikationen sowieso. Auskommentieren der leeren Destruktor lassen Sie den compiler vollständig inline-code.Take-away ist, dass Sie ab jetzt, in jeder Klasse, Schreibe ich auskommentiert leere Destruktoren zu lassen, wissen die Menschen, die Destruktor führt nichts am Ziel, die sehr gleiche Weise, die Leute kommentieren Sie die leere Ausnahme-Spezifikation `/* throw () */, um anzuzeigen, dass der Destruktor kann nicht werfen.
Hoffe, das hilft.
InformationsquelleAutor der Antwort Gregory Pakosz
Den leeren Destruktor, die Sie definiert, die aus der Klasse hat eine ähnliche Semantik in Bezug auf die meisten, aber nicht in allen.
Explizit, die implizit definierte Destruktor
1) ist ein inline public-member (Ihr nicht inline)
2) wird bezeichnet als trivial destructor (notwendig, um triviale Arten, die in Gewerkschaften, yours nicht)
3) ist eine Ausnahme-Spezifikation (throw(), yours nicht)
InformationsquelleAutor der Antwort Faisal Vali
Ja, das leeren Destruktor ist die gleiche wie die automatisch generierten. Ich habe immer nur lassen Sie den compiler generieren Sie automatisch; ich glaube nicht, dass es notwendig ist, geben Sie den Destruktor explizit, es sei denn, etwas außergewöhnliches zu machen: stellen Sie virtuelle oder private, zu sagen.
InformationsquelleAutor der Antwort David Seiler
Ich Stimme mit David außer, dass ich würde sagen, es ist generell eine gute Praxis, definieren Sie einen virtuellen Destruktor d.h.
verpassen virtuelle Destruktor kann zu Speicherverlust führen, weil Menschen, die Erben von deiner Klasse " Foo " kann nicht bemerkt haben, dass Ihr Destruktor nie aufgerufen!!
InformationsquelleAutor der Antwort oscarkuo
Ich würde sagen, am besten setzen Sie die leere Erklärung, es sagt, dass alle zukünftigen Betreuer, dass es nicht ein versehen, und du wirklich meinst den Standardwert verwenden.
InformationsquelleAutor der Antwort Ape-inago
Einer leeren definition ist in Ordnung, da die definition verwiesen werden kann
Die leere Erklärung ist täuschend ähnlich in Aussehen
noch lädt der gefürchtete keine definition für virtuelle Destruktor Fehler
InformationsquelleAutor der Antwort