Dies ist ein vereinfachtes Beispiel zur Veranschaulichung der Frage:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
Also ist B für die Aktualisierung eines Teils von C verantwortlich. Ich habe den Code durch Lint geführt und es ging um das Referenzmitglied: Lint # 1725 . Hier geht es darum, auf Standardkopien und -zuweisungen zu achten, was fair genug ist, aber Standardkopien und -zuweisungen sind auch mit Zeigern schlecht, sodass es dort wenig Vorteile gibt.
Ich versuche immer, Referenzen zu verwenden, wo ich kann, da nackte Zeiger unsicher darüber einführen, wer für das Löschen dieses Zeigers verantwortlich ist. Ich bevorzuge es, Objekte nach Wert einzubetten, aber wenn ich einen Zeiger benötige, verwende ich auto_ptr in den Mitgliedsdaten der Klasse, der der Zeiger gehört, und gebe das Objekt als Referenz weiter.
Ich würde im Allgemeinen nur dann einen Zeiger in Mitgliedsdaten verwenden, wenn der Zeiger null sein oder sich ändern könnte. Gibt es andere Gründe, Zeiger gegenüber Referenzen für Datenelemente vorzuziehen?
Stimmt es, dass ein Objekt, das eine Referenz enthält, nicht zuweisbar sein sollte, da eine Referenz nach der Initialisierung nicht geändert werden sollte?
quelle
Antworten:
Vermeiden Sie Referenzmitglieder, da sie die Möglichkeiten der Implementierung einer Klasse einschränken (einschließlich, wie Sie bereits erwähnt haben, die Implementierung eines Zuweisungsoperators verhindern) und keine Vorteile für das bieten, was die Klasse bieten kann.
Beispielprobleme:
zerlegen(bis C ++ 0x, jedenfallsbearbeiten: C ++ hat jetzt delegierende Konstruktoren )..
Operator usw.) aus, verhält sich jedoch wie ein Zeiger (kann baumeln) - z. B. rät Google Style Guide davon abquelle
Meine eigene Faustregel:
quelle
Objekte sollten selten Zuweisungen und andere Dinge wie Vergleiche zulassen. Wenn Sie ein Geschäftsmodell mit Objekten wie "Abteilung", "Mitarbeiter", "Direktor" betrachten, ist es schwer vorstellbar, dass ein Mitarbeiter einem anderen zugewiesen wird.
Für Geschäftsobjekte ist es daher sehr gut, Eins-zu-Eins- und Eins-zu-Viele-Beziehungen als Referenzen und nicht als Zeiger zu beschreiben.
Und wahrscheinlich ist es in Ordnung, eine Eins-oder-Null-Beziehung als Zeiger zu beschreiben.
Also kein 'wir können nicht zuweisen' dann Faktor.
Viele Programmierer gewöhnen sich nur an Zeiger, und deshalb finden sie Argumente, um die Verwendung von Referenzen zu vermeiden.
Wenn Sie einen Zeiger als Mitglied haben, werden Sie oder ein Mitglied Ihres Teams gezwungen, den Zeiger vor der Verwendung immer wieder zu überprüfen, mit dem Kommentar "Nur für den Fall". Wenn ein Zeiger Null sein kann, wird der Zeiger wahrscheinlich als eine Art Flag verwendet, was schlecht ist, da jedes Objekt seine eigene Rolle spielen muss.
quelle
Verwenden Sie Referenzen, wenn Sie können, und Zeiger, wenn Sie müssen.
quelle
In einigen wichtigen Fällen ist eine Zuweisbarkeit einfach nicht erforderlich. Hierbei handelt es sich häufig um einfache Algorithmus-Wrapper, die die Berechnung erleichtern, ohne den Gültigkeitsbereich zu verlassen. Solche Objekte sind Hauptkandidaten für Referenzmitglieder, da Sie sicher sein können, dass sie immer eine gültige Referenz enthalten und niemals kopiert werden müssen.
Stellen Sie in solchen Fällen sicher, dass der Zuweisungsoperator (und häufig auch der Kopierkonstruktor) nicht verwendbar ist (indem Sie ihn erben
boost::noncopyable
oder als privat deklarieren).Wie bereits von Benutzern kommentiert, gilt dies jedoch nicht für die meisten anderen Objekte. Hier kann die Verwendung von Referenzelementen ein großes Problem sein und sollte generell vermieden werden.
quelle
Da jeder allgemeine Regeln zu verteilen scheint, biete ich zwei an:
Verwenden Sie niemals Verweise als Klassenmitglieder. Ich habe dies in meinem eigenen Code noch nie getan (außer um mir selbst zu beweisen, dass ich mit dieser Regel Recht hatte) und kann mir keinen Fall vorstellen, in dem ich dies tun würde. Die Semantik ist zu verwirrend und es ist wirklich nicht das, wofür Referenzen entworfen wurden.
Verwenden Sie immer, immer Referenzen, wenn Sie Parameter an Funktionen übergeben, mit Ausnahme der Basistypen, oder wenn der Algorithmus eine Kopie erfordert.
Diese Regeln sind einfach und haben mir gute Dienste geleistet. Ich überlasse es anderen, Regeln für die Verwendung intelligenter Zeiger (aber bitte nicht auto_ptr) als Klassenmitglieder festzulegen.
quelle
Ja zu: Stimmt es, dass ein Objekt, das eine Referenz enthält, nicht zuweisbar sein sollte, da eine Referenz nach der Initialisierung nicht geändert werden sollte?
Meine Faustregeln für Datenmitglieder:
quelle
Ja. Lesbarkeit Ihres Codes. Ein Zeiger macht deutlicher, dass das Element eine Referenz ist (ironischerweise :)) und kein enthaltenes Objekt, denn wenn Sie es verwenden, müssen Sie es de-referenzieren. Ich weiß, dass einige Leute denken, dass das altmodisch ist, aber ich denke immer noch, dass es einfach Verwirrung und Fehler verhindert.
quelle
Ich rate von Referenzdatenmitgliedern ab, da Sie nie wissen, wer von Ihrer Klasse abgeleitet wird und was sie möglicherweise tun möchten. Möglicherweise möchten sie das referenzierte Objekt nicht verwenden, aber als Referenz haben Sie sie gezwungen, ein gültiges Objekt anzugeben. Ich habe mir das genug angetan, um keine Referenzdatenelemente mehr zu verwenden.
quelle
Wenn ich die Frage richtig verstehe ...
Referenz als Funktionsparameter anstelle des Zeigers: Wie Sie bereits betont haben, macht ein Zeiger nicht klar, wem die Bereinigung / Initialisierung des Zeigers gehört. Bevorzugen Sie einen gemeinsamen Punkt, wenn Sie einen Zeiger möchten, der Teil von C ++ 11 ist, und einen schwachen_ptr, wenn die Gültigkeit der Daten nicht über die Lebensdauer der Klasse garantiert ist, die die Daten akzeptiert, auf die verwiesen wird.; auch ein Teil von C ++ 11. Die Verwendung einer Referenz als Funktionsparameter garantiert, dass die Referenz nicht null ist. Sie müssen die Sprachfunktionen untergraben, um dies zu umgehen, und wir kümmern uns nicht um lose Kanonencodierer.
Referenz aa Mitgliedsvariable: Wie oben in Bezug auf die Datengültigkeit. Dies garantiert, dass die Daten, auf die verwiesen wird und auf die dann verwiesen wird, gültig sind.
Wenn Sie die Verantwortung für die Gültigkeit von Variablen auf einen früheren Punkt im Code verschieben, wird nicht nur der spätere Code (in Ihrem Beispiel die Klasse A) bereinigt, sondern auch der verwendeten Person klar gemacht.
In Ihrem Beispiel, das etwas verwirrend ist (ich würde wirklich versuchen, eine klarere Implementierung zu finden), ist das von B verwendete A für die Lebensdauer des B garantiert, da B ein Mitglied von A ist, sodass eine Referenz dies verstärkt und ist (vielleicht) klarer.
Und nur für den Fall (was eine geringe Wahrscheinlichkeit ist, da dies in Ihrem Codekontext keinen Sinn ergibt), würde eine andere Alternative, einen nicht referenzierten Parameter ohne Zeiger A zu verwenden, A kopieren und das Paradigma unbrauchbar machen - I. Ich glaube wirklich nicht, dass du das als Alternative meinst.
Dies garantiert auch, dass Sie die referenzierten Daten nicht ändern können, wenn ein Zeiger geändert werden kann. Ein const-Zeiger würde nur funktionieren, wenn der referenzierte / Zeiger auf Daten nicht veränderbar wäre.
Zeiger sind nützlich, wenn der A-Parameter für B nicht garantiert eingestellt wurde oder neu zugewiesen werden konnte. Und manchmal ist ein schwacher Zeiger einfach zu ausführlich für die Implementierung, und eine gute Anzahl von Leuten weiß entweder nicht, was ein schwacher_ptr ist, oder sie mögen sie einfach nicht.
Zerreiße diese Antwort bitte :)
quelle