4 Stimmen

Frage zum Löschen eines Zeigers. Aus welcher Klasse soll er gelöscht werden?

Ich habe zwei vier Klassen:

  • HauptKlasse (Klasse, in der alles beginnt)
  • XmlReader (Klasse, die zum Parsen einer Xml-Datei verwendet wird)
  • SerialPortSettings (enthält Informationen über die aus der Xml-Datei gelesene serielle Schnittstelle, z. B. Baudrate, Port usw.)
  • SerialPortListener (nimmt in seinem Konstruktor einen Verweis auf ein SerialPortSettings-Objekt auf)

HauptKlasse hat eine Methode, um Dinge aus einer Xml-Datei zu lesen. In dieser Methode wird zunächst eine Instanz von XmlReader und gibt ihm eine xml-Datei als Konstruktorparameter. Dieser xmlReader muss nur innerhalb dieser Methode existieren:

XmlReader xmlReader (xmlFile);

Der xmlReader parst die xmlDatei. HauptKlasse erhält Zugriff auf die Xml-Sachen durch Aufruf von get-methods in XmlReader . So weit ist alles gut.

Eine der Methoden ist jedoch XmlReader bietet, ist eine Methode, die ein Objekt des Typs SerialPortSettings auf der Grundlage der aus der xml-Datei gelesenen Informationen:

SerialPortSettings* XmlReader::getSerialPortSettings() {
  .... // reading stuff from xml file
  return new SerialPortSettings(baudRate, dataBits, comport);
}

Diese Methode wird aufgerufen von HauptKlasse und der Rückgabewert wird in einem Zeiger gespeichert:

SerialPortSettings* settings = xmlReader.getSerialPortSettings();

Die nächste Aufgabe der MainClass ist die Erstellung einer SerialPortListener (eine Member-Variable, die so lange existieren muss, bis MainClass verlassen wird). Der SerialPortListener nimmt in seinem Konstruktor einen Verweis auf SerialPortSettings entgegen:

m_serialPortListener = new SerialPortListener(*settings);

Daher muss SerialPortSettings auch so lange existieren, bis MainClass beendet wird, daher habe ich es als Zeiger angelegt.

Hier ist also der Hinweis:

In der SerialPortListener destructor habe ich versucht, die SerialPortSettings -Gegenstand:

SerialPortListener::~SerialPortListener() {
  delete &m_settings;
}

Dann im HauptKlasse Destruktor habe ich die SerialPortListener -Gegenstand:

MainClass::~MainClass() {
  delete m_serialPortListener;
} 

Das schlägt fehl. Ich erhalte eine Fehlermeldung, die besagt, dass ich etwas zweimal in der Hauptklasse gelöscht habe:

*** glibc detected *** ./ioserver: double free or corruption (out): 0x00860d80 ***

Wenn ich das Löschen &m_settings aus SerialPortListener entferne, funktioniert es gut. Aber wann sollte der Zeiger gelöscht werden? Was ist das Richtige zu tun? Ich möchte wirklich, dass mein Xml-Reader das SerialPortSettings-Objekt erstellt, anstatt alle Informationen (Baudrate, Port usw.) an MainClass zurückzugeben und das SerialPortSettings-Objekt selbst zu erstellen.

1voto

Cheers and hth. - Alf Punkte 138555

Eine gute Lösung ist es, einfach die xmlReader::getSerialPortSettings ein zurückgeben SerialPortSettings nach Wert.

Lassen Sie den Compiler die Optimierung durchführen.

Wenn Sie jedoch Zeigerlebensdauern behandeln müssen, verwenden Sie intelligente Zeiger , wie zum Beispiel std::auto_ptr o boost::shared_ptr . Der Schlüsselgedanke ist die Definition des Eigentums. Der Eigentümer (der im Fall von boost::shared_ptr ist die Sammlung von intelligenten Zeigern, die auf das Objekt verweisen) ist für das Löschen verantwortlich - niemand sonst.

Prost & hth.,

0voto

Satya Punkte 4428

Der Zeiger sollte am Ende von MainClass gelöscht werden.

0voto

unwind Punkte 377331

Es macht (zumindest für mich) keinen Sinn, die delete auf eine Referenz.

Es wäre viel sauberer, wenn der XML-Reader keine neuen Objekte erstellen würde; behandeln Sie SerialPortSettings als einen "dummen" Container und übergeben Sie einfach einen Verweis, um ihn mit Daten aus dem XML zu füllen:

XmlReader::getSerialPortSettings(SerialPortSettings& settings);

die eigentliche Instanz kann dann eine lokale Variable im Hauptprogramm sein und wird (diesmal per const-Referenz) an die serielle Schnittstelle übergeben, wenn sie erstellt wird:

SerialPortSettings portSettings;
m_xmlReader->getSerialPortSettings(portSettings);
m_serialPort = new SerialPort(portSettings);

die Lebensdauer der Einstellungsinstanz ist dann natürlich dieselbe wie der Bereich, in dem sie sich befindet, da sie nur eine lokale Variable ist.

Wenn die Methode in der Hauptklasse, die XML liest, beendet werden muss, bevor die serielle Schnittstelle den Anwendungsbereich verlässt, könnten Sie die Einstellungen stattdessen zu einer Mitgliedsvariablen der Hauptklasse machen.

0voto

badgerr Punkte 7604

Was ist der Datentyp von m_settings? Ist es ein SerialPortSettings* oder ein SerialPortSettings? Wenn letzteres der Fall ist, können Sie es nicht einfach so löschen, da es auf dem Stack alloziert ist. Wenn es sich um einen Zeiger handelt, brauchen Sie den Referenzoperator nicht. Schreiben Sie einfach delete m_settings;

0voto

Mark Ransom Punkte 283960

Ein einfacher Tippfehler in Ihrer Löschung:

delete &m_settings;

sein sollte:

delete m_settings;

Für jeden Zeiger sollten Sie entscheiden, wer owns den Zeiger, und das sollte derjenige sein, der ihn löscht.

Oder Sie können einen intelligenten Zeiger verwenden, z. B. shared_ptr und das Problem gänzlich zu beseitigen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X