Sind Heap-zugewiesene Member-Referenzen eine schreckliche Idee? Warum?

7

Um dieses Problem bestmöglich zu erklären, habe ich ein einfaches Beispiel erstellt. Angenommen, ich habe eine Klasse Blob wie folgt:

%Vor%

A Blob kann vom Ersteller (alias Programmer) erzeugt werden, an diesem Punkt wird ein personalName ausgewählt und, da es das Privileg hat, eine 1. Generation Blob zu sein, wird es ausgewählt eigene familyName .

Alternativ kann ein Blob erstellt werden, indem ein existierendes Blob erzeugt wird. An diesem Punkt wählt es sein eigenes personalName aus, teilt aber ein familyName mit allen anderen Blob s, in die geklont wurde diese Familie. Wenn ein Blob den Familiennamen ändert, wird der Name automatisch für alle anderen Familienmitglieder geändert.

Bisher klingt das alles gut und gut, bis ich beim Schreiben des Blob -Konstruktors folgendes sehe:

%Vor%

Eek! Speicher auf dem Heap zuordnen und dann einer Referenzvariablen zuweisen ?! Das sieht erschreckend aus!

Sind meine Instinkte richtig, dass da etwas sehr falsch ist, oder fühlt es sich nur komisch an, weil es kein allgemeines Muster ist? Wenn etwas nicht stimmt, was ist es? Warum ist das ein schlechtes Design?

Hinweis: Es wäre wichtig, diesen speicherzuhaltenden Speicher durch Referenzzählen und Löschen des Speichers freizugeben, wenn der letzte Blob zerstört ist, oder auf andere Weise.

    
Cory Klein 23.08.2011, 20:55
quelle

3 Antworten

14

Es ist nur dann sinnvoll, eine Referenz als Klassenmitglied zu speichern, wenn:

  1. Die Daten gehören nicht der Klasse und die Klasse ist nicht dafür verantwortlich, sie freizugeben;
  2. Die Lebensdauer des referenzierten Objekts ist garantiert länger als die Lebensdauer des enthaltenen Objekts.

Ihr Beispiel verstößt gegen Regel 1.

    
Mark Ransom 23.08.2011, 21:18
quelle
8

Ich denke, der "stinkende" Teil speichert die Variable als Verweis auf eine Zeichenfolge, da es schwierig werden kann, den Überblick darüber zu behalten, ob es sich um ein gültiges Objekt handelt. Warum nicht etwas wie:

verwenden %Vor%

BEARBEITEN

Gemäß Praetorian's Vorschlag können Sie vermeiden, dass Sie manuell Speicher vollständig zuweisen:

%Vor%     
Dawson 23.08.2011 21:02
quelle
1

Ein Argument wäre die Konsistenz: operator new gibt einen Zeiger zurück und operator delete nimmt einen Zeiger, daher wird erwartet, dass der Typ, der für die Referenzierung dynamisch zugewiesener Objekte verwendet wird, auch Zeiger und nicht Referenz ist. Dies ist ein ernsthaftes Argument: Wenn Sie widersprüchlich sind und sich ohne guten Grund gegen Programmierergewohnheiten wehren, verwirren Sie sie und züchten Fehler. Niemand würde normalerweise eine Funktion erwarten, die einen Verweis zurückgibt, um neue Objekte auf dem Heap zu erstellen, die der aufrufende Code dann löschen muss, so dass früher oder später jemand es vergessen wird.

Aber es gibt auch pragmatische Gründe dafür, dass Zeiger neu zugewiesen werden können und dass sie auf null gesetzt werden können, was sie für die Handhabung dynamisch zugeordneter Objekte bequemer macht. In Ihrem Beispiel ist die Blob-Klasse für das Aufrufen von delete auf dem Referenzelement verantwortlich. Normalerweise würden Sie das im Destruktor tun. Aber stellen Sie sich vor, Sie möchten den Speicher früher freigeben: Mit Zeigern können Sie ihnen nach dem Aufruf von delete null zuweisen, und dann lassen Sie ihren Destruktor sicher wieder delete aufrufen, mit Bezugselementen bleibt Ihnen eine dangling-Referenz, die Sie nicht tun können irgendetwas über.

Ein noch gravierenderes Problem ist die Ausnahmesicherheit: Wenn Blob eine längere Initialisierungsliste oder einen nicht leeren Body hätte, könnte der Konstruktor nach dem Aufruf von pickFamilyName () werfen. In diesem Fall wird der Destruktor nicht aufgerufen und Sie haben ein Speicherleck. Im Idealfall würden Sie RAII dafür verwenden, aber mit Zeigern ist es auch möglich, den Zeiger in der Initialisierungsliste auf Null zu setzen und dann auf das neu erstellte Objekt im Konstruktorkörper in einem try / catch-Block zu verweisen, der das Objekt sicherstellen würde wird gelöscht, selbst wenn der Konstruktor den Befehl auslöst und es keinen Destruktor gibt. Dies kann wiederum nicht mit Referenzen erfolgen.

    
AndrzejJ 23.08.2011 22:22
quelle

Tags und Links